diff --git a/webapi/Services/ImageService/Class1.cs b/webapi/Services/ImageService/Class1.cs new file mode 100644 index 0000000..9aad34a --- /dev/null +++ b/webapi/Services/ImageService/Class1.cs @@ -0,0 +1,5 @@ +namespace ImageService { + public class Class1 { + + } +} \ No newline at end of file diff --git a/webapi/Services/ImageService/ImageService.csproj b/webapi/Services/ImageService/ImageService.csproj new file mode 100644 index 0000000..132c02c --- /dev/null +++ b/webapi/Services/ImageService/ImageService.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/webapi/WeatherForecast.sln b/webapi/WeatherForecast.sln index d349497..d59ef98 100644 --- a/webapi/WeatherForecast.sln +++ b/webapi/WeatherForecast.sln @@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensionsTests", "Tests\Ex EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageService", "Services\ImageService\ImageService.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {04CB9827-AA6D-4708-A26D-8420C842506D}.Debug|Any CPU.Build.0 = Debug|Any CPU {04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.ActiveCfg = Release|Any CPU {04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.Build.0 = Release|Any CPU + {16552644-D7EE-4B4A-A725-79909A8103DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16552644-D7EE-4B4A-A725-79909A8103DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16552644-D7EE-4B4A-A725-79909A8103DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16552644-D7EE-4B4A-A725-79909A8103DE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -82,6 +88,7 @@ Global {B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5} {43315A1D-9E09-4398-84B9-A9D9D623AE5A} = {216302C2-64DE-4AE7-BC14-BDAC5B732472} {04CB9827-AA6D-4708-A26D-8420C842506D} = {216302C2-64DE-4AE7-BC14-BDAC5B732472} + {16552644-D7EE-4B4A-A725-79909A8103DE} = {113EE574-E047-4727-AA36-841F845504D5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E2805D02-2425-424C-921D-D97341B76F73} diff --git a/webapi/WeatherForecast/Controllers/BlogItemController.cs b/webapi/WeatherForecast/Controllers/BlogItemController.cs index d3c58d0..fad234d 100644 --- a/webapi/WeatherForecast/Controllers/BlogItemController.cs +++ b/webapi/WeatherForecast/Controllers/BlogItemController.cs @@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class BlogItemController : ControllerBase { - private readonly ILogger _logger; private readonly IBlogItemService _blogItemService; /// /// /// - /// /// public BlogItemController( - ILogger logger, IBlogItemService blogItemService ) { - _logger = logger; _blogItemService = blogItemService; } diff --git a/webapi/WeatherForecast/Controllers/BlogItemsController.cs b/webapi/WeatherForecast/Controllers/BlogItemsController.cs index 43f832a..6230e07 100644 --- a/webapi/WeatherForecast/Controllers/BlogItemsController.cs +++ b/webapi/WeatherForecast/Controllers/BlogItemsController.cs @@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers; [Route("api/[controller]")] public class BlogItemsController : ControllerBase { - private readonly ILogger _logger; private readonly IBlogItemsService _blogItemsService; /// /// /// - /// /// public BlogItemsController( - ILogger logger, IBlogItemsService blogItemsService ) { - _logger = logger; _blogItemsService = blogItemsService; } diff --git a/webapi/WeatherForecast/Controllers/CategoryItemController.cs b/webapi/WeatherForecast/Controllers/CategoryItemController.cs index 17b2e33..a0efb1f 100644 --- a/webapi/WeatherForecast/Controllers/CategoryItemController.cs +++ b/webapi/WeatherForecast/Controllers/CategoryItemController.cs @@ -16,18 +16,14 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class CategoryItemController : ControllerBase { - private readonly ILogger _logger; private readonly ICategoryItemService _categoryItemService; /// /// /// - /// /// public CategoryItemController( - ILogger logger, ICategoryItemService categoryItemService) { - _logger = logger; _categoryItemService = categoryItemService; } diff --git a/webapi/WeatherForecast/Controllers/CategoryItemsController.cs b/webapi/WeatherForecast/Controllers/CategoryItemsController.cs index 02ab1dd..96270b8 100644 --- a/webapi/WeatherForecast/Controllers/CategoryItemsController.cs +++ b/webapi/WeatherForecast/Controllers/CategoryItemsController.cs @@ -15,22 +15,16 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class CategoryItemsController : ControllerBase { - private readonly ILogger _logger; private readonly ICategoryItemsService _categoryItemsService; /// /// /// - /// /// public CategoryItemsController( - ILogger logger, ICategoryItemsService categoryItemsService ) { - _logger = logger; _categoryItemsService = categoryItemsService; - - } /// diff --git a/webapi/WeatherForecast/Controllers/ContentController.cs b/webapi/WeatherForecast/Controllers/ContentController.cs index 67a2419..5e55410 100644 --- a/webapi/WeatherForecast/Controllers/ContentController.cs +++ b/webapi/WeatherForecast/Controllers/ContentController.cs @@ -15,7 +15,6 @@ namespace WeatherForecast.Controllers; [Route("api/[controller]")] public class ContentController : ControllerBase { - private readonly ILogger _logger; private readonly IContentService _contentService; /// @@ -24,10 +23,8 @@ public class ContentController : ControllerBase { /// /// public ContentController( - ILogger logger, IContentService contentService ) { - _logger = logger; _contentService = contentService; } diff --git a/webapi/WeatherForecast/Controllers/FileController.cs b/webapi/WeatherForecast/Controllers/FileController.cs index 86ea2fb..79c5343 100644 --- a/webapi/WeatherForecast/Controllers/FileController.cs +++ b/webapi/WeatherForecast/Controllers/FileController.cs @@ -30,6 +30,19 @@ namespace WeatherForecast.Controllers { /// /// /// + /// + /// + /// + [HttpPost("{siteId}/{userId}")] + public IActionResult Post([FromRoute] Guid siteId, [FromRoute] Guid userId, IFormFile file) { + var result = _fileService.Post(siteId, userId, file); + return result.ToActionResult(); + } + + /// + /// https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/ + /// + /// /// /// /// diff --git a/webapi/WeatherForecast/Controllers/ShopCartItemController.cs b/webapi/WeatherForecast/Controllers/ShopCartItemController.cs index bbc169c..dd0ac2d 100644 --- a/webapi/WeatherForecast/Controllers/ShopCartItemController.cs +++ b/webapi/WeatherForecast/Controllers/ShopCartItemController.cs @@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class ShopCartItemController : ControllerBase { - private readonly ILogger _logger; private readonly IShopCartItemService _shopCartItemService; /// /// /// - /// /// public ShopCartItemController( - ILogger logger, IShopCartItemService shopCartItemService ) { - _logger = logger; _shopCartItemService = shopCartItemService; } diff --git a/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs b/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs index c494b95..0e84366 100644 --- a/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs +++ b/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs @@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class ShopCartItemsController : ControllerBase { - private readonly ILogger _logger; private readonly IShopCartItemsService _shopCartItemsService; /// /// /// - /// /// public ShopCartItemsController( - ILogger logger, IShopCartItemsService shopCartItemsService ) { - _logger = logger; _shopCartItemsService = shopCartItemsService; } diff --git a/webapi/WeatherForecast/Controllers/ShopItemController.cs b/webapi/WeatherForecast/Controllers/ShopItemController.cs index 7b4e865..01de26b 100644 --- a/webapi/WeatherForecast/Controllers/ShopItemController.cs +++ b/webapi/WeatherForecast/Controllers/ShopItemController.cs @@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers { [Route("api/[controller]")] public class ShopItemController : ControllerBase { - private readonly ILogger _logger; private readonly IShopItemService _shopItemService; /// /// /// - /// /// public ShopItemController( - ILogger logger, IShopItemService shopItemService ) { - _logger = logger; _shopItemService = shopItemService; } diff --git a/webapi/WeatherForecast/Controllers/ShopItemsController.cs b/webapi/WeatherForecast/Controllers/ShopItemsController.cs index b91eac7..b89a615 100644 --- a/webapi/WeatherForecast/Controllers/ShopItemsController.cs +++ b/webapi/WeatherForecast/Controllers/ShopItemsController.cs @@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers; [Route("api/[controller]")] public class ShopItemsController : ControllerBase { - private readonly ILogger _logger; private readonly IShopItemsService _shopItemsService; /// /// /// - /// /// public ShopItemsController( - ILogger logger, IShopItemsService shopCatalogService ) { - _logger = logger; _shopItemsService = shopCatalogService; } diff --git a/webapi/WeatherForecast/Controllers/WeatherForecastController.cs b/webapi/WeatherForecast/Controllers/WeatherForecastController.cs index 9b51b2a..e74f658 100644 --- a/webapi/WeatherForecast/Controllers/WeatherForecastController.cs +++ b/webapi/WeatherForecast/Controllers/WeatherForecastController.cs @@ -10,20 +10,14 @@ namespace WeatherForecast.Controllers; [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; + private static readonly string[] Summaries = new[] { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; /// /// /// - /// - public WeatherForecastController(ILogger logger) { - _logger = logger; - } + public WeatherForecastController() { } /// /// diff --git a/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs b/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs new file mode 100644 index 0000000..d1bb4ea --- /dev/null +++ b/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs @@ -0,0 +1,217 @@ +using DomainResults.Common; +using ExtensionMethods; + +namespace WeatherForecast.Services.Abstractions { + + /// + /// + /// + public enum FileCategory { + /// + /// + /// + Document, + + /// + /// + /// + Image, + + /// + /// + /// + Video + } + + /// + /// + /// + public class FileSignature { + + /// + /// + /// + public List Signatures { get; private set; } + + /// + /// + /// + public string ContentType { get; private set; } + + /// + /// + /// + public FileCategory FileCategory { get; private set; } + + /// + /// + /// + /// + /// + /// + public FileSignature(List signatures, string contentType, FileCategory fileCategory) { + Signatures = signatures; + ContentType = contentType; + FileCategory = fileCategory; + } + } + + /// + /// + /// + public abstract class FileServiceBase { + + /// + /// https://gist.github.com/qti3e/6341245314bf3513abb080677cd1c93b + /// + private readonly Dictionary _data = new() { + #region Documents + { + ".pdf", + new FileSignature(new List { + "0,25504446" + }, "application/pdf", FileCategory.Document) + }, + { + ".rtf", + new FileSignature(new List { + "0,7B5C72746631" + }, "application/rtf", FileCategory.Document) + }, + { + ".doc", + new FileSignature(new List { + "0,0D444F43", + "0,CF11E0A1B11AE100", + "0,D0CF11E0A1B11AE1", + "0,DBA52D00", + "512,ECA5C100" + }, "application/msword", FileCategory.Document) + }, + { + ".xls", + new FileSignature(new List { + "512,0908100000060500", + "0,D0CF11E0A1B11AE1", + "512,FDFFFFFF04", + "512,FDFFFFFF20000000" + }, "application/vnd.ms-excel", FileCategory.Document) + }, + { + ".ppt", + new FileSignature(new List { + "512,006E1EF0", + "512,0F00E803", + "512,A0461DF0", + "0,D0CF11E0A1B11AE1", + "512,FDFFFFFF04" + }, "application/vnd.ms-powerpoint", FileCategory.Document) + }, + { + ".docx", + new FileSignature(new List { + "0,504B030414000600" + }, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", FileCategory.Document) + }, + { + ".xlsx", + new FileSignature(new List { + "0,504B030414000600" + }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", FileCategory.Document) + }, + { + ".pptx", + new FileSignature(new List { + "0,504B030414000600" + }, "application/vnd.openxmlformats-officedocument.presentationml.presentation", FileCategory.Document) + }, + #endregion + + #region Images + { + ".jpg", + new FileSignature(new List { + "0,FFD8" + }, "image/jpeg", FileCategory.Image) + }, + { + ".jpeg", + new FileSignature(new List { + "0,FFD8" + }, "image/jpeg", FileCategory.Image) + }, + { + ".jpe", + new FileSignature(new List { + "0,FFD8" + }, "image/jpeg", FileCategory.Image) + }, + { + ".jfif", + new FileSignature(new List { + "0,FFD8" + }, "image/jpeg", FileCategory.Image) + }, + + { + ".png", + new FileSignature(new List { + "0,89504E470D0A1A0A" + }, "image/png", FileCategory.Image) + }, + + { + ".webp", + new FileSignature(new List { + "0,52494646" + }, "image/webp", FileCategory.Image) + } + #endregion + }; + + + /// + /// Don't rely on or trust the FileName property without validation. + /// + /// + /// + /// + /// + private protected (FileCategory?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType) { + + var data = _data.SingleOrDefault(x => x.Key == Path.GetExtension(fileName).ToLower()).Value; + + if (data == null) + return IDomainResult.NotFound(); + + // check content type + if (contentType != data.ContentType) + return IDomainResult.Failed(); + + // check signatures + foreach (var signature in data.Signatures) { + var splitString = signature.Split(","); + + var offset = splitString[0].ToInt(); + var signBytes = Enumerable.Range(0, splitString[1].Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(splitString[1].Substring(x, 2), 16)) + .ToArray(); + + var sample = new byte[signBytes.Length]; + Buffer.BlockCopy(bytes, offset, sample, 0, signBytes.Length); + + int x = sample.Length ^ signBytes.Length; + + // https://www.syncfusion.com/succinctly-free-ebooks/application-security-in-net-succinctly/comparing-byte-arrays + for (int i = 0; i < sample.Length && i < signBytes.Length; ++i) { + x |= sample[i] ^ signBytes[i]; + } + + if (x == 0) return IDomainResult.Success(data.FileCategory); ; + } + + return IDomainResult.Failed(); ; + } + } +} diff --git a/webapi/WeatherForecast/Services/BlogItemService.cs b/webapi/WeatherForecast/Services/BlogItemService.cs index baf2f7c..b72408d 100644 --- a/webapi/WeatherForecast/Services/BlogItemService.cs +++ b/webapi/WeatherForecast/Services/BlogItemService.cs @@ -128,6 +128,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -160,6 +161,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new BlogItemResponseModel(item, categories)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -194,6 +196,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new BlogItemResponseModel(item, categories, locale)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -229,6 +232,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(item.Id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -253,6 +257,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/BlogItemsService.cs b/webapi/WeatherForecast/Services/BlogItemsService.cs index 278bc1f..f11734a 100644 --- a/webapi/WeatherForecast/Services/BlogItemsService.cs +++ b/webapi/WeatherForecast/Services/BlogItemsService.cs @@ -103,6 +103,7 @@ namespace WeatherForecast.Services { : IDomainResult.NotFound(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -117,6 +118,7 @@ namespace WeatherForecast.Services { return _blogCatalogDataProvider.DeleteAll(siteId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/CategoryItemService.cs b/webapi/WeatherForecast/Services/CategoryItemService.cs index 4ae0e88..5bf4ed8 100644 --- a/webapi/WeatherForecast/Services/CategoryItemService.cs +++ b/webapi/WeatherForecast/Services/CategoryItemService.cs @@ -101,6 +101,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -120,6 +121,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new CategoryItemResponseModel(item)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -141,6 +143,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new CategoryItemResponseModel(item, locale)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -172,6 +175,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(item.Id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -195,6 +199,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/CategoryItemsService.cs b/webapi/WeatherForecast/Services/CategoryItemsService.cs index bf219eb..393de15 100644 --- a/webapi/WeatherForecast/Services/CategoryItemsService.cs +++ b/webapi/WeatherForecast/Services/CategoryItemsService.cs @@ -71,6 +71,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(items.Select(x => new CategoryItemResponseModel(x)).ToList()); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed?>(ex.Message); } } @@ -85,6 +86,7 @@ namespace WeatherForecast.Services { return _categoryDataProvider.DeleteAll(siteId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/ContentService.cs b/webapi/WeatherForecast/Services/ContentService.cs index 5c1a0be..fcdcaa4 100644 --- a/webapi/WeatherForecast/Services/ContentService.cs +++ b/webapi/WeatherForecast/Services/ContentService.cs @@ -57,6 +57,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new ContentResponseModel(content)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/FileService.cs b/webapi/WeatherForecast/Services/FileService.cs index c634a61..46f89a8 100644 --- a/webapi/WeatherForecast/Services/FileService.cs +++ b/webapi/WeatherForecast/Services/FileService.cs @@ -1,6 +1,8 @@ -using DataProviders; +using Core; +using DataProviders; using DataProviders.Buckets; using DomainResults.Common; +using WeatherForecast.Services.Abstractions; namespace WeatherForecast.Services { @@ -8,6 +10,16 @@ namespace WeatherForecast.Services { /// /// public interface IFileService { + + /// + /// + /// + /// + /// + /// + /// + (Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file); + /// /// /// @@ -30,7 +42,7 @@ namespace WeatherForecast.Services { /// /// /// - public class FileService : IFileService { + public class FileService : FileServiceBase, IFileService { private readonly ILogger _logger; private readonly IImagesBucketDataProvider _imageBucketDataProvider; @@ -48,6 +60,51 @@ namespace WeatherForecast.Services { _imageBucketDataProvider = imageBucketDataProvider; } + /// + /// + /// + /// + /// + /// + /// + public (Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file) { + try { + if (!(file.Length > 0)) + return IDomainResult.Failed(); + + using var ms = new MemoryStream(); + file.CopyTo(ms); + var bytes = ms.ToArray(); + + var (fileCategory, signatureResult) = CheckFileSignature(file.FileName, bytes, file.ContentType); + + if(!signatureResult.IsSuccess || fileCategory == null) + return IDomainResult.Failed(); + + var bucketFile = new BucketFile(file.FileName, bytes, file.ContentType); + + IDomainResult result; + Guid? fileId; + + switch (fileCategory) { + case FileCategory.Image: + (fileId, result) = _imageBucketDataProvider.Upload(siteId, userId, bucketFile); + break; + default: + return IDomainResult.Failed(); + } + + if (!result.IsSuccess || fileId == null) + return IDomainResult.Failed(); + + return IDomainResult.Success(fileId); + } + catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); + return IDomainResult.Failed(ex.Message); + } + } + /// /// /// @@ -64,6 +121,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(file); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -80,6 +138,7 @@ namespace WeatherForecast.Services { return _imageBucketDataProvider.DeleteOne(siteId, userId, fileId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/FilesService.cs b/webapi/WeatherForecast/Services/FilesService.cs index 76767c1..673cc9f 100644 --- a/webapi/WeatherForecast/Services/FilesService.cs +++ b/webapi/WeatherForecast/Services/FilesService.cs @@ -1,7 +1,7 @@ using DataProviders; using DataProviders.Buckets; using DomainResults.Common; -using Microsoft.AspNetCore.Mvc; +using WeatherForecast.Services.Abstractions; namespace WeatherForecast.Services { @@ -31,7 +31,7 @@ namespace WeatherForecast.Services { /// /// /// - public class FilesService : IFilesService { + public class FilesService : FileServiceBase, IFilesService { private readonly ILogger _logger; private readonly IImagesBucketDataProvider _imageBucketDataProvider; @@ -60,14 +60,15 @@ namespace WeatherForecast.Services { try { // Don't rely on or trust the FileName property without validation. + if(files.Any(x => !(x.Length > 0))) + return IDomainResult.Failed?>(); + var newFiles = new List(); foreach (var formFile in files) { - if (formFile.Length > 0) { - using var ms = new MemoryStream(); - formFile.CopyTo(ms); + using var ms = new MemoryStream(); + formFile.CopyTo(ms); - newFiles.Add(new BucketFile(formFile.FileName, ms.ToArray(), formFile.ContentType)); - } + newFiles.Add(new BucketFile(formFile.FileName, ms.ToArray(), formFile.ContentType)); } var (list, result) = _imageBucketDataProvider.UploadMany(siteId, userId, newFiles); @@ -78,6 +79,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(list); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed?> (ex.Message); } } @@ -93,6 +95,7 @@ namespace WeatherForecast.Services { return _imageBucketDataProvider.DeletMany(siteId, userId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/ShopCartItemService.cs b/webapi/WeatherForecast/Services/ShopCartItemService.cs index 30077b6..5956275 100644 --- a/webapi/WeatherForecast/Services/ShopCartItemService.cs +++ b/webapi/WeatherForecast/Services/ShopCartItemService.cs @@ -108,6 +108,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -138,6 +139,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new ShopCartItemResponseModel(item, cartItem, Enumeration.FromDisplayName(locale ?? "en-US"))); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -173,6 +175,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(item.Id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -197,6 +200,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/ShopCartItemsService.cs b/webapi/WeatherForecast/Services/ShopCartItemsService.cs index 3e4d6e5..13e82b6 100644 --- a/webapi/WeatherForecast/Services/ShopCartItemsService.cs +++ b/webapi/WeatherForecast/Services/ShopCartItemsService.cs @@ -88,6 +88,7 @@ namespace WeatherForecast.Services { : IDomainResult.NotFound?>(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed?>(ex.Message); } } @@ -103,6 +104,7 @@ namespace WeatherForecast.Services { return _shopCartDataProvider.DeleteAll(siteId, userId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/ShopItemService.cs b/webapi/WeatherForecast/Services/ShopItemService.cs index 2f36382..705e6c3 100644 --- a/webapi/WeatherForecast/Services/ShopItemService.cs +++ b/webapi/WeatherForecast/Services/ShopItemService.cs @@ -133,6 +133,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } @@ -166,6 +167,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new ShopItemResponseModel(item, categories)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -199,6 +201,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(new ShopItemResponseModel(item, categories, locale)); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -233,6 +236,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(item.Id); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -256,6 +260,7 @@ namespace WeatherForecast.Services { return IDomainResult.Success(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } diff --git a/webapi/WeatherForecast/Services/ShopItemsService.cs b/webapi/WeatherForecast/Services/ShopItemsService.cs index c8086d0..4951bda 100644 --- a/webapi/WeatherForecast/Services/ShopItemsService.cs +++ b/webapi/WeatherForecast/Services/ShopItemsService.cs @@ -105,6 +105,7 @@ namespace WeatherForecast.Services { : IDomainResult.NotFound(); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } } @@ -119,6 +120,7 @@ namespace WeatherForecast.Services { return _shopCatalogDataProvider.DeleteAll(siteId); } catch (Exception ex) { + _logger.LogError(ex, "Unhandled exception"); return IDomainResult.Failed(ex.Message); } }