diff --git a/Api/Controllers/EventController.cs b/Api/Controllers/EventController.cs
index 4036e1159bc8232eb55b8f8a81238e8673fb265b..bb15c836d4bb12f4a6642f742fa414ea61851ca4 100644
--- a/Api/Controllers/EventController.cs
+++ b/Api/Controllers/EventController.cs
@@ -3,8 +3,13 @@ using BusinessLayer.DTOs.Event;
 using BusinessLayer.Services.EventService;
 using BusinessLayer.Utils.Filters;
 using BusinessLayer.Utils.Ordering;
+using BusinessLayer.DTOs.Image;
+using BusinessLayer.Services.ImageService;
+using BusinessLayer.Utils.Enums;
 using Mapster;
 using Microsoft.AspNetCore.Mvc;
+using MimeMapping;
+using System.IO.Compression;
 
 namespace Api.Controllers
 {
@@ -13,10 +18,12 @@ namespace Api.Controllers
     public class EventController : Controller
     {
         private readonly IEventService _eventService;
+        private readonly IImageService _imageService;
 
-        public EventController(IEventService eventService)
+        public EventController(IEventService eventService, IImageService imageService)
         {
             _eventService = eventService;
+            _imageService = imageService;
         }
 
         [HttpGet("{eventId:guid}")]
@@ -94,5 +101,102 @@ namespace Api.Controllers
 
             return Ok();
         }
+
+
+        [HttpGet]
+        [Route("{eventId:guid}/img")]
+        public async Task<IActionResult> DownloadImages([FromRoute] Guid eventId, [FromQuery] ImageType type)
+        {
+            var images = await _imageService.GetImagesAsync(eventId, OwnerEntityType.Event, type);
+            if (type == ImageType.Avatar)
+            {
+                var image = images.FirstOrDefault();
+
+                return image is not null
+                    ? File(image.Data, MimeUtility.GetMimeMapping(image.Name))
+                    : NotFound();
+            }
+
+            using var memoryStream = new MemoryStream();
+            using var zip = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
+
+            foreach (var image in images)
+            {
+                var entry = zip.CreateEntry(image.Name, CompressionLevel.Fastest);
+                using var streamWriter = entry.Open();
+                await streamWriter.WriteAsync(image.Data.AsMemory(0, image.Data.Length));
+            }
+
+            zip.Dispose();
+
+            return File(memoryStream.ToArray(), "application/zip", "gallery.zip");
+        }
+
+        [HttpPost]
+        [Route("{eventId:guid}/avatar")]
+        public async Task<IActionResult> UploadAvatar([FromRoute] Guid eventId, [FromForm] IFormFile avatar)
+        {
+            var extension = Path.GetExtension(avatar.FileName);
+
+            if (extension is null || avatar.ContentType != MimeUtility.GetMimeMapping(avatar.FileName))
+            {
+                return BadRequest("File has no extension or extension doesn't match the content type.");
+            }
+
+            using var stream = new MemoryStream();
+            await avatar.CopyToAsync(stream);
+            ImageUploadDTO image = new()
+            {
+                Data = stream.ToArray(),
+                EntityId = eventId,
+                EntityType = OwnerEntityType.Event,
+                ImageType = ImageType.Avatar,
+                Extension = extension
+            };
+
+            return await _imageService.SaveImageAsync(image)
+                ? CreatedAtAction(nameof(UploadAvatar), null)
+                : BadRequest("The provided file is not an image.");
+        }
+
+        [HttpPost]
+        [Route("{eventId:guid}/gallery")]
+        public async Task<IActionResult> UploadGalleryImages([FromRoute] Guid eventId, [FromForm] List<IFormFile> images)
+        {
+            List<ImageUploadDTO> dtos = new List<ImageUploadDTO>();
+            foreach (var img in images)
+            {
+                var extension = Path.GetExtension(img.FileName);
+
+                if (extension is null || img.ContentType != MimeUtility.GetMimeMapping(img.FileName))
+                {
+                    return BadRequest("File has no extension or extension doesn't match the content type.");
+                }
+
+                using var stream = new MemoryStream();
+                await img.CopyToAsync(stream);
+
+                dtos.Add(new ImageUploadDTO()
+                {
+                    Data = stream.ToArray(),
+                    EntityId = eventId,
+                    EntityType = OwnerEntityType.Event,
+                    ImageType = ImageType.Gallery,
+                    Extension = extension
+                });
+            }
+            return await _imageService.SaveImagesAsync([.. dtos])
+                ? CreatedAtAction(nameof(UploadGalleryImages), null)
+                : BadRequest();
+        }
+
+        [HttpDelete]
+        [Route("{eventId:guid}/img")]
+        public async Task<IActionResult> DeleteImage([FromRoute] Guid eventId, [FromQuery] string imageName)
+        {
+            return await _imageService.RemoveImageAsync(eventId, OwnerEntityType.Event, imageName)
+                ? Ok()
+                : NotFound("The image or the restaurant does not exist.");
+        }
     }
 }
diff --git a/Api/Controllers/RestaurantController.cs b/Api/Controllers/RestaurantController.cs
index 32b38062d3dd3156746937441835326472ec47ae..cf0d4454bbbf7ac974c37b2be393d91c9ef8e429 100644
--- a/Api/Controllers/RestaurantController.cs
+++ b/Api/Controllers/RestaurantController.cs
@@ -1,11 +1,17 @@
+using Api.Models;
+using Api.Models.Restaurant;
+using BusinessLayer.DTOs.Image;
+using BusinessLayer.Services.ImageService;
+using BusinessLayer.Utils.Enums;
 using BusinessLayer.DTOs.Restaurant;
 using BusinessLayer.Services.RestaurantService;
 using BusinessLayer.Services.RestaurantMaintainerService;
 using BusinessLayer.Utils.Filters;
 using BusinessLayer.Utils.Ordering;
 using Microsoft.AspNetCore.Mvc;
-using Api.Models.Restaurant;
 using Mapster;
+using MimeMapping;
+using System.IO.Compression;
 
 namespace Api.Controllers
 {
@@ -13,10 +19,12 @@ namespace Api.Controllers
     [ApiController]
     public class RestaurantController(
         IRestaurantService restaurantService,
-        IRestaurantMaintainerService restaurantMaintainerService) : Controller
+        IRestaurantMaintainerService restaurantMaintainerService,
+        IImageService imageService) : Controller
     {
         private readonly IRestaurantService _restaurantService = restaurantService;
         private readonly IRestaurantMaintainerService _restaurantMaintainerService = restaurantMaintainerService;
+        private readonly IImageService _imageService = imageService;
 
         [HttpGet]
         [Route("{restaurantId:guid}")]
@@ -120,5 +128,103 @@ namespace Api.Controllers
                 ? Ok()
                 : NotFound();
         }
+
+        [HttpGet]
+        [Route("{restaurantId:guid}/img")]
+        public async Task<IActionResult> DownloadImages([FromRoute] Guid restaurantId, [FromQuery] ImageType type)
+        {
+            var images = await _imageService.GetImagesAsync(restaurantId, OwnerEntityType.Restaurant, type);
+            if (type == ImageType.Avatar)
+            {
+                var image = images.FirstOrDefault();
+
+                return image is not null
+                    ? File(image.Data, MimeUtility.GetMimeMapping(image.Name))
+                    : NotFound();
+            }
+
+            using var memoryStream = new MemoryStream();
+            using var zip = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
+
+            foreach (var image in images)
+            {
+                var entry = zip.CreateEntry(image.Name, CompressionLevel.Fastest);
+                using var streamWriter = entry.Open();
+                await streamWriter.WriteAsync(image.Data.AsMemory(0, image.Data.Length));
+            }
+
+            // The zip will be invalid otherwise.
+            zip.Dispose();
+
+            return File(memoryStream.ToArray(), "application/zip", "gallery.zip");
+        }
+
+        [HttpPost]
+        [Route("{restaurantId:guid}/avatar")]
+        public async Task<IActionResult> UploadAvatar([FromRoute] Guid restaurantId, [FromForm] IFormFile avatar)
+        {
+            var extension = Path.GetExtension(avatar.FileName);
+
+            if (extension is null || avatar.ContentType != MimeUtility.GetMimeMapping(avatar.FileName))
+            {
+                return BadRequest("File has no extension or extension doesn't match the content type.");
+            }
+
+            using var stream = new MemoryStream();
+            await avatar.CopyToAsync(stream);
+
+            ImageUploadDTO image = new()
+            {
+                Data = stream.ToArray(),
+                EntityId = restaurantId,
+                EntityType = OwnerEntityType.Restaurant,
+                ImageType = ImageType.Avatar,
+                Extension = extension
+            };
+
+            return await _imageService.SaveImageAsync(image)
+                ? CreatedAtAction(nameof(UploadAvatar), null)
+                : BadRequest("The provided file is not an image.");
+        }
+
+        [HttpPost]
+        [Route("{restaurantId:guid}/gallery")]
+        public async Task<IActionResult> UploadGalleryImages([FromRoute] Guid restaurantId, [FromForm] List<IFormFile> images)
+        {
+            List<ImageUploadDTO> dtos = new List<ImageUploadDTO>();
+            foreach (var img in images)
+            {
+                var extension = Path.GetExtension(img.FileName);
+
+                if (extension is null || img.ContentType != MimeUtility.GetMimeMapping(img.FileName))
+                {
+                    return BadRequest("File has no extension or extension doesn't match the content type.");
+                }
+
+                using var stream = new MemoryStream();
+                await img.CopyToAsync(stream);
+
+                dtos.Add(new ImageUploadDTO()
+                {
+                    Data = stream.ToArray(),
+                    EntityId = restaurantId,
+                    EntityType = OwnerEntityType.Restaurant,
+                    ImageType = ImageType.Gallery,
+                    Extension = extension
+                });
+            }
+            return await _imageService.SaveImagesAsync([.. dtos])
+                ? CreatedAtAction(nameof(UploadGalleryImages), null)
+                : BadRequest();
+        }
+
+        [HttpDelete]
+        [Route("{restaurantId:guid}/img")]
+        public async Task<IActionResult> DeleteImage([FromRoute] Guid restaurantId, [FromQuery] string imageName)
+        {
+            return await _imageService.RemoveImageAsync(restaurantId, OwnerEntityType.Restaurant, imageName)
+                ? Ok()
+                : NotFound("The image or the restaurant does not exist.");
+        }
     }
 }
diff --git a/Api/Controllers/ReviewController.cs b/Api/Controllers/ReviewController.cs
index d87c747e1d6af34816de1e2d41c9ecc044a5cc84..b7be804792b2cbfd1cb8190738e3906608806a43 100644
--- a/Api/Controllers/ReviewController.cs
+++ b/Api/Controllers/ReviewController.cs
@@ -3,8 +3,14 @@ using BusinessLayer.DTOs.Review;
 using BusinessLayer.Services.ReviewService;
 using BusinessLayer.Utils.Filters;
 using BusinessLayer.Utils.Ordering;
+using BusinessLayer.Services.ImageService;
+using BusinessLayer.DTOs.Image;
 using Mapster;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using MimeMapping;
+using System.IO.Compression;
+using BusinessLayer.Utils.Enums;
 
 namespace Api.Controllers
 {
@@ -13,10 +19,12 @@ namespace Api.Controllers
     public class ReviewController : Controller
     {
         private readonly IReviewService _service;
-        public ReviewController(IReviewService service)
+        public readonly IImageService _imageService;
+
+        public ReviewController(IReviewService service, IImageService imageService)
         {
             _service = service;
-
+            _imageService = imageService;
         }
 
         [HttpGet]
@@ -90,6 +98,69 @@ namespace Api.Controllers
                 : NotFound("Review does not exist.");
         }
 
+        [HttpGet]
+        [Route("{reviewId:guid}/img")]
+        public async Task<IActionResult> DownloadImages([FromRoute] Guid reviewId)
+        {
+
+            var images = await _imageService.GetImagesAsync(reviewId, OwnerEntityType.Review, ImageType.Gallery);
+
+            using var memoryStream = new MemoryStream();
+            using var zip = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);
+
+            foreach (var image in images)
+            {
+                var entry = zip.CreateEntry(image.Name, CompressionLevel.Fastest);
+                using var streamWriter = entry.Open();
+                await streamWriter.WriteAsync(image.Data.AsMemory(0, image.Data.Length));
+            }
+
+            // The zip will be invalid otherwise.
+            zip.Dispose();
+
+            return File(memoryStream.ToArray(), "application/zip", "gallery.zip");
+        }
+
+        [HttpPost]
+        [Route("{reviewId:guid}/gallery")]
+        public async Task<IActionResult> UploadGalleryImages([FromRoute] Guid reviewId, [FromForm] List<IFormFile> images)
+        {
+            List<ImageUploadDTO> dtos = new List<ImageUploadDTO>();
+            foreach (var img in images)
+            {
+                var extension = Path.GetExtension(img.FileName);
+
+                if (extension is null || img.ContentType != MimeUtility.GetMimeMapping(img.FileName))
+                {
+                    return BadRequest("File has no extension or extension doesn't match the content type.");
+                }
+
+                using var stream = new MemoryStream();
+                await img.CopyToAsync(stream);
+
+                dtos.Add(new ImageUploadDTO()
+                {
+                    Data = stream.ToArray(),
+                    EntityId = reviewId,
+                    EntityType = OwnerEntityType.Review,
+                    ImageType = ImageType.Gallery,
+                    Extension = extension
+                });
+            }
+            return await _imageService.SaveImagesAsync([.. dtos])
+                ? CreatedAtAction(nameof(UploadGalleryImages), null)
+                : BadRequest();
+        }
+
+        [HttpDelete]
+        [Route("{reviewId:guid}/img")]
+        public async Task<IActionResult> DeleteImage([FromRoute] Guid reviewId, [FromQuery] string imageName)
+        {
+            return await _imageService.RemoveImageAsync(reviewId, OwnerEntityType.Review, imageName)
+                ? Ok()
+                : NotFound("The image or the review does not exist.");
+        }
+
         private static bool UpdateEmpty(ReviewUpdateModel data)
         {
             return data.Content is null && data.FoodRating is null
diff --git a/Api/Controllers/UserController.cs b/Api/Controllers/UserController.cs
index 2a96bc4a7b7bb9d03cf5f735f0c33ea4166f9041..3b2b91f8591246bdbfe8d9d5d75b087b7ed6b4fa 100644
--- a/Api/Controllers/UserController.cs
+++ b/Api/Controllers/UserController.cs
@@ -1,18 +1,24 @@
-using Api.Models.User;
+using Api.Models;
+using Api.Models.User;
+using BusinessLayer.DTOs.Image;
+using BusinessLayer.Services.ImageService;
+using BusinessLayer.Utils.Enums;
 using BusinessLayer.DTOs.User;
 using BusinessLayer.Services.UserService;
 using BusinessLayer.Utils.Filters;
 using BusinessLayer.Utils.Ordering;
 using Mapster;
 using Microsoft.AspNetCore.Mvc;
+using MimeMapping;
 
 namespace Api.Controllers
 {
     [Route("/api/[controller]")]
     [ApiController]
-    public class UserController(IUserService userService) : Controller
+    public class UserController(IUserService userService, IImageService imageService) : Controller
     {
         private readonly IUserService _userService = userService;
+        private readonly IImageService _imageService = imageService;
 
         [HttpGet]
         [Route("{userId:guid}")]
@@ -94,5 +100,55 @@ namespace Api.Controllers
                 ? NotFound("User not found.")
                 : Ok();
         }
+
+        [HttpGet]
+        [Route("{userId:guid}/img")]
+        public async Task<IActionResult> DownloadImages([FromRoute] Guid userId)
+        {
+            // User only has an avatar image.
+            var images = await _imageService.GetImagesAsync(userId, OwnerEntityType.User, ImageType.Avatar);
+
+            var image = images.FirstOrDefault();
+
+            return image is not null
+                ? File(image.Data, MimeUtility.GetMimeMapping(image.Name))
+                : NotFound();
+        }
+
+        [HttpPost]
+        [Route("{userId:guid}/avatar")]
+        public async Task<IActionResult> UploadAvatar([FromRoute] Guid userId, [FromForm] IFormFile avatar)
+        {
+            var extension = Path.GetExtension(avatar.FileName);
+
+            if (extension is null || avatar.ContentType != MimeUtility.GetMimeMapping(avatar.FileName))
+            {
+                return BadRequest("File has no extension or extension doesn't match the content type.");
+            }
+
+            using var stream = new MemoryStream();
+            await avatar.CopyToAsync(stream);
+            ImageUploadDTO image = new()
+            {
+                Data = stream.ToArray(),
+                EntityId = userId,
+                EntityType = OwnerEntityType.User,
+                ImageType = ImageType.Avatar,
+                Extension = extension
+            };
+
+            return await _imageService.SaveImageAsync(image)
+                ? CreatedAtAction(nameof(UploadAvatar), null)
+                : BadRequest("The provided file is not an image.");
+        }
+
+        [HttpDelete]
+        [Route("{userId:guid}/img")]
+        public async Task<IActionResult> DeleteImage([FromRoute] Guid userId, [FromQuery] string imageName)
+        {
+            return await _imageService.RemoveImageAsync(userId, OwnerEntityType.User, imageName)
+                ? Ok()
+                : NotFound("The image or the review does not exist.");
+        }
     }
 }
diff --git a/Api/Program.cs b/Api/Program.cs
index 3faee96c7c84b74a3404be3ab9e57bc8478b45f2..8866be6498afd6acc0485e1a56e8cffb418aeb12 100644
--- a/Api/Program.cs
+++ b/Api/Program.cs
@@ -6,7 +6,10 @@ using BusinessLayer.Services.UserService;
 using BusinessLayer.Services.ReviewAggregateService;
 using BusinessLayer.Services.ReviewCommentService;
 using BusinessLayer.Services.ReviewService;
+using BusinessLayer.Services.ImageService;
 using DAL.Data;
+using DAL.ImagePersistence.ImageStorage;
+using DAL.ImagePersistence.StorageRollbackManager;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.OpenApi.Models;
 using Elastic.Extensions.Logging;
@@ -41,6 +44,10 @@ builder.Services.AddScoped<IReviewService, ReviewService>();
 builder.Services.AddScoped<IReviewAggregateResultService, ReviewAggregateResultService>();
 builder.Services.AddScoped<IReviewCommentService, ReviewCommentService>();
 
+builder.Services.AddTransient<IStorageRollbackManager, SimpleRollbackManager>();
+builder.Services.AddScoped<IImageStorage, FileSystemImageStorage>();
+builder.Services.AddScoped<IImageService, ImageService>();
+
 builder.Services.AddControllers();
 
 // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
diff --git a/BusinessLayer/DTOs/Image/ImageDTO.cs b/BusinessLayer/DTOs/Image/ImageDTO.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2b8b93227cf1c98b62e646b5c8a48622147dff9a
--- /dev/null
+++ b/BusinessLayer/DTOs/Image/ImageDTO.cs
@@ -0,0 +1,10 @@
+namespace BusinessLayer.DTOs.Image
+{
+    public record ImageDTO
+    {
+        public byte[] Data { get; set; } = [];
+        public required string Name { get; set; }
+        public required string ImageType { get; set; }
+        public required string Extension { get; set; }
+    }
+}
diff --git a/BusinessLayer/DTOs/Image/ImageUploadDTO.cs b/BusinessLayer/DTOs/Image/ImageUploadDTO.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8d000711efd7c6af69c58f17728a911003e8f0b
--- /dev/null
+++ b/BusinessLayer/DTOs/Image/ImageUploadDTO.cs
@@ -0,0 +1,13 @@
+using BusinessLayer.Utils.Enums;
+
+namespace BusinessLayer.DTOs.Image
+{
+    public record ImageUploadDTO
+    {
+        public byte[] Data { get; set; } = [];
+        public Guid EntityId { get; set; }
+        public OwnerEntityType EntityType { get; set; }
+        public ImageType ImageType { get; set; }
+        public required string Extension { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/BusinessLayer/Services/ImageService/IImageService.cs b/BusinessLayer/Services/ImageService/IImageService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4716e5eac886cfce12a28cfad6d2c4e4b64bc9c8
--- /dev/null
+++ b/BusinessLayer/Services/ImageService/IImageService.cs
@@ -0,0 +1,17 @@
+using BusinessLayer.DTOs.Image;
+using BusinessLayer.Utils.Enums;
+
+namespace BusinessLayer.Services.ImageService
+{
+    public interface IImageService
+    {
+        public string[] GetImagePaths(Guid entityId, OwnerEntityType entityType, ImageType imageType);
+        public Task<List<ImageDTO>> GetImagesAsync(Guid entityId, OwnerEntityType entityType, ImageType imageType);
+
+        public Task<bool> SaveImageAsync(ImageUploadDTO imageUploadDTO, bool checkEntityExistence = true);
+
+        public Task<bool> SaveImagesAsync(ImageUploadDTO[] imageUploadDTOs);
+
+        public Task<bool> RemoveImageAsync(Guid entityId, OwnerEntityType entityType, string imageName);
+    }
+}
diff --git a/BusinessLayer/Services/ImageService/ImageService.cs b/BusinessLayer/Services/ImageService/ImageService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..beed2c5e45a5fb1be54490ce13340db483e9aeb0
--- /dev/null
+++ b/BusinessLayer/Services/ImageService/ImageService.cs
@@ -0,0 +1,157 @@
+using BusinessLayer.DTOs.Image;
+using BusinessLayer.Utils.Enums;
+using DAL.Constants;
+using DAL.Data;
+using DAL.ImagePersistence.ImageStorage;
+using DAL.ImagePersistence.Model;
+using Mapster;
+using Microsoft.EntityFrameworkCore;
+
+namespace BusinessLayer.Services.ImageService
+{
+    public class ImageService : IImageService
+    {
+        private readonly RestaurantDBContext _dbContext;
+        private readonly IImageStorage _imageStorage;
+
+        public ImageService(RestaurantDBContext dbContext, IImageStorage imageStorage)
+        {
+            _dbContext = dbContext;
+            _imageStorage = imageStorage;
+        }
+
+        public async Task<List<ImageDTO>> GetImagesAsync(Guid entityId, OwnerEntityType entityType, ImageType imageType)
+        {
+            if (!await EntityExists(entityId, entityType))
+            {
+                return [];
+            }
+
+            var nameFilter = imageType == ImageType.All
+                ? "*"
+                : imageType.ToString("g") + "*";
+
+            var images = await _imageStorage.ReadImagesAsync(new BaseImagePathData
+            {
+                OwnerEntityName = entityType.ToString("g"),
+                OwnerEntityId = entityId.ToString(),
+                ImageType = imageType.ToString("g")
+            },
+            nameFilter);
+
+            TypeAdapterConfig<LoadedImageData, ImageDTO>
+                .NewConfig()
+                .Map(dest => dest.Name, src => Path.GetFileName(src.Path));
+
+            return images.Select(image => image.Adapt<ImageDTO>()).ToList();
+        }
+
+        public async Task<bool> SaveImageAsync(ImageUploadDTO imageUploadDTO, bool checkEntityExistence = true)
+        {
+            if (checkEntityExistence && !await EntityExists(imageUploadDTO.EntityId, imageUploadDTO.EntityType))
+            {
+                return false;
+            }
+
+            bool replace = imageUploadDTO.ImageType == ImageType.Avatar;
+
+            return await _imageStorage.SaveImageAsync(
+                new ImageStorageData
+                {
+                    Data = imageUploadDTO.Data,
+                    Path = new GenericImagePathData
+                    {
+                        OwnerEntityName = imageUploadDTO.EntityType.ToString("g"),
+                        OwnerEntityId = imageUploadDTO.EntityId.ToString(),
+                        ImageType = imageUploadDTO.ImageType.ToString("g"),
+                        Extension = imageUploadDTO.Extension,
+                    }
+                },
+                replace);
+        }
+
+        public async Task<bool> SaveImagesAsync(ImageUploadDTO[] imageUploadDTOs)
+        {
+            var first = imageUploadDTOs.First();
+            if (!await EntityExists(first.EntityId, first.EntityType))
+            {
+                return false;
+            }
+
+            TypeAdapterConfig<ImageUploadDTO, ImageStorageData>
+                .NewConfig()
+                .Map(dest => dest.Path,
+                     src => new GenericImagePathData
+                     {
+                         OwnerEntityName = src.EntityType.ToString("g"),
+                         OwnerEntityId = src.EntityId.ToString(),
+                         ImageType = src.ImageType.ToString("g"),
+                         Extension = src.Extension,
+                     });
+
+            return await _imageStorage.SaveImagesAsync(
+                imageUploadDTOs
+                    .Select(i => i.Adapt<ImageStorageData>())
+                    .ToList(),
+                false);
+        }
+
+        private async Task<bool> EntityExists(Guid entityId, OwnerEntityType entityType)
+        {
+            return entityType switch
+            {
+                OwnerEntityType.User => await _dbContext.Users
+                    .AnyAsync(u => u.Id == entityId && u.DeletedAt == null),
+
+                OwnerEntityType.Restaurant => await _dbContext.Restaurants
+                    .AnyAsync(r => r.Id == entityId && r.DeletedAt == null),
+
+                OwnerEntityType.Event => await _dbContext.Events
+                    .AnyAsync(e => e.Id == entityId && e.DeletedAt == null),
+
+                OwnerEntityType.Review => await _dbContext.Reviews
+                    .AnyAsync(r => r.Id == entityId && r.DeletedAt == null),
+
+                _ => false,
+            };
+        }
+
+        public async Task<bool> RemoveImageAsync(Guid entityId, OwnerEntityType entityType, string imageName)
+        {
+            if (!await EntityExists(entityId, entityType))
+            {
+                return false;
+            }
+
+            return _imageStorage.RemoveImage(new SpecificImagePathData
+            {
+                OwnerEntityName = entityType.ToString("g"),
+                OwnerEntityId = entityId.ToString(),
+                ImageType = ImageType.All.ToString("g"),
+                Name = imageName
+            });
+        }
+
+        public string[] GetImagePaths(Guid entityId, OwnerEntityType entityType, ImageType imageType)
+        {
+            return _imageStorage.GetImagePaths(new BaseImagePathData
+            {
+                OwnerEntityName = entityType.ToString("g"),
+                OwnerEntityId = entityId.ToString(),
+                ImageType = ImageType.All.ToString("g")
+            },
+            ComposeNameFilter(imageType));
+
+        }
+
+        private string ComposeNameFilter(ImageType type)
+        {
+            return type switch
+            {
+                ImageType.Avatar => Paths.AvatarImageName + "*",
+                ImageType.Gallery => Paths.GalleryImageName + "*",
+                _ => "*"
+            };
+        }
+    }
+}
diff --git a/BusinessLayer/Utils/Enums/ImageType.cs b/BusinessLayer/Utils/Enums/ImageType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c3e687097fa93558ef60cd927a7d28255265d53b
--- /dev/null
+++ b/BusinessLayer/Utils/Enums/ImageType.cs
@@ -0,0 +1,9 @@
+namespace BusinessLayer.Utils.Enums
+{
+    public enum ImageType
+    {
+        Avatar,
+        Gallery,
+        All
+    }
+}
diff --git a/BusinessLayer/Utils/Enums/OwnerEntityType.cs b/BusinessLayer/Utils/Enums/OwnerEntityType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d3f2875eef3bf0f873df8e1aa9763d164a68d049
--- /dev/null
+++ b/BusinessLayer/Utils/Enums/OwnerEntityType.cs
@@ -0,0 +1,10 @@
+namespace BusinessLayer.Utils.Enums
+{
+    public enum OwnerEntityType
+    {
+        User,
+        Event,
+        Restaurant,
+        Review
+    }
+}
diff --git a/DAL/Constants/Paths.cs b/DAL/Constants/Paths.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3e847a447de9ab2459d5c58889f4b81eefea7458
--- /dev/null
+++ b/DAL/Constants/Paths.cs
@@ -0,0 +1,11 @@
+namespace DAL.Constants
+{
+    public static class Paths
+    {
+        public const string ImageDirPath = "img";
+        public const string AvatarImageName = "Avatar";
+        public const string GalleryImageName = "Gallery";
+        public const string ImageMimePrefix = "image";
+        public const string ImageIdSeparator = "-";
+    }
+}
diff --git a/DAL/DAL.csproj b/DAL/DAL.csproj
index 767c3ca4ff77640a5dc14f45c5dcc041b1a22c74..1b0623f76daa1070ff88b9612a193543f974be28 100644
--- a/DAL/DAL.csproj
+++ b/DAL/DAL.csproj
@@ -14,7 +14,8 @@
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
-  </ItemGroup>
+    <PackageReference Include="MimeMapping" Version="3.0.1" />
+  </ItemGroup>  
 
   <ItemGroup>
     <Folder Include="Migrations\" />
diff --git a/DAL/ImagePersistence/ImageStorage/FileSystemImageStorage.cs b/DAL/ImagePersistence/ImageStorage/FileSystemImageStorage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a25edb5378f55ae63d5bc8b95af7f6475138784c
--- /dev/null
+++ b/DAL/ImagePersistence/ImageStorage/FileSystemImageStorage.cs
@@ -0,0 +1,213 @@
+using DAL.Constants;
+using DAL.ImagePersistence.Model;
+using DAL.ImagePersistence.StorageRollbackManager;
+using DAL.ImagePersistence.Utils;
+
+namespace DAL.ImagePersistence.ImageStorage
+{
+    public class FileSystemImageStorage : IImageStorage
+    {
+        public readonly IStorageRollbackManager _rollbackManager;
+
+        public FileSystemImageStorage(IStorageRollbackManager rollbackManager)
+        {
+            _rollbackManager = rollbackManager;
+        }
+
+        public string[] GetImagePaths(BaseImagePathData path, string nameFilter)
+        {
+            return Directory.GetFiles(path.ComposeDirectoryPath(), nameFilter);
+        }
+
+        public async Task<List<LoadedImageData>> ReadImagesAsync(BaseImagePathData path, string nameFilter)
+        {
+            var dirPath = path.ComposeDirectoryPath();
+
+            if (!Directory.Exists(dirPath))
+            {
+                return [];
+            }
+
+            var images = Directory.GetFiles(dirPath, nameFilter);
+
+            List<LoadedImageData> result = [];
+
+            foreach (var imagePath in images)
+            {
+                var mime = MimeMapping.MimeUtility.GetMimeMapping(imagePath);
+                if (mime == null || !mime.StartsWith(Paths.ImageMimePrefix))
+                {
+                    continue;
+                }
+
+                var image = await LoadImage(imagePath, mime);
+                if (image != null)
+                {
+                    result.Add(image);
+                }
+            }
+
+            return result;
+        }
+
+        public async Task<LoadedImageData?> ReadImageAsync(SpecificImagePathData path)
+        {
+            var imagePath = path.ComposeSpecificFilePath();
+
+            if (!File.Exists(imagePath))
+            {
+                return null;
+            }
+
+            var mime = MimeMapping.MimeUtility.GetMimeMapping(imagePath);
+            if (mime == null || !mime.StartsWith(Paths.ImageMimePrefix))
+            {
+                return null;
+            }
+
+            return await LoadImage(imagePath, mime);
+        }
+
+        public bool RemoveImage(SpecificImagePathData path)
+        {
+            string filePath = path.ComposeSpecificFilePath();
+
+            if (!File.Exists(filePath))
+            {
+                return false;
+            }
+
+            File.Delete(filePath);
+
+            return true;
+        }
+
+        public async Task<bool> SaveImagesAsync(List<ImageStorageData> images, bool replace)
+        {
+            var first = images.FirstOrDefault();
+
+            if (first == null)
+            {
+                // The list is empty -> we saved all images :-)
+                return true;
+            }
+
+            _ = Directory.CreateDirectory(first.Path.ComposeDirectoryPath());
+
+            /*
+             * Precalculating the expected ID for each image so we don't have to
+             * resolve the new ID every time we save an image. The check for duplication
+             * still occurs.
+             */
+            int? expectedId = first.Path.PrefetchExpectedIdentifier(replace);
+
+            if (expectedId == null || expectedId < 0)
+            {
+                return false;
+            }
+
+            foreach (var image in images)
+            {
+                image.Path.Identifier = expectedId;
+                expectedId++;
+
+                if (!await StoreImage(image, replace, true))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public async Task<bool> SaveImageAsync(ImageStorageData image, bool replace)
+        {
+            _ = Directory.CreateDirectory(image.Path.ComposeDirectoryPath());
+
+            return await StoreImage(image, replace, false);
+        }
+
+        private static async Task<LoadedImageData> LoadImage(string path, string mime)
+        {
+            using var file = File.OpenRead(path);
+            byte[] data = new byte[file.Length];
+            await file.ReadAsync(data);
+
+            return new LoadedImageData
+            {
+                Path = path,
+                Data = data,
+                Mime = mime
+            };
+        }
+
+        private async Task<bool> StoreImage(ImageStorageData image, bool replace, bool useRollback)
+        {
+            string? imagePath;
+
+            try
+            {
+                imagePath = image.Path.ResolveImagePath(replace);
+            }
+            catch (Exception)
+            {
+                if (useRollback)
+                {
+                    await _rollbackManager.RollbackAsync();
+                }
+                throw;
+            }
+
+            if (imagePath is null)
+            {
+                if (useRollback)
+                {
+                    await _rollbackManager.RollbackAsync();
+                }
+                return false;
+            }
+
+            try
+            {
+                return await WriteFile(image, replace, useRollback, imagePath);
+            }
+            catch (Exception)
+            {
+                if (useRollback)
+                {
+                    await _rollbackManager.RollbackAsync();
+                }
+                throw;
+            }
+        }
+
+        private async Task<bool> WriteFile(ImageStorageData image, 
+            bool replace, bool useRollback, string imagePath)
+        {
+            bool isOverwrite = replace && File.Exists(imagePath);
+            
+            using var file = File.Open(imagePath, FileMode.OpenOrCreate);
+
+            if (useRollback)
+            {
+                byte[] contents = new byte[file.Length];
+
+                if (isOverwrite)
+                {
+                    await file.ReadAsync(contents);
+                    file.Seek(0, SeekOrigin.Begin);
+                }
+
+                _rollbackManager.AddEntry(new RollbackEntry
+                {
+                    Path = imagePath,
+                    OriginalData = isOverwrite ? contents : []
+                });
+            }
+
+            await file.WriteAsync(image.Data);
+            _rollbackManager.Commit();
+            return true;
+        }
+    }
+}
diff --git a/DAL/ImagePersistence/ImageStorage/IImageStorage.cs b/DAL/ImagePersistence/ImageStorage/IImageStorage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d39dcacfc0355ac45b8c2be2b7de71b948169118
--- /dev/null
+++ b/DAL/ImagePersistence/ImageStorage/IImageStorage.cs
@@ -0,0 +1,20 @@
+using DAL.ImagePersistence.Model;
+
+namespace DAL.ImagePersistence.ImageStorage
+{
+    public interface IImageStorage
+    {
+        public string[] GetImagePaths(BaseImagePathData path, string nameFilter);
+
+        public Task<LoadedImageData?> ReadImageAsync(SpecificImagePathData path);
+
+        public Task<bool> SaveImageAsync(ImageStorageData image, bool replace);
+
+        public Task<bool> SaveImagesAsync(List<ImageStorageData> image, bool replace);
+
+        public Task<List<LoadedImageData>> ReadImagesAsync(BaseImagePathData path,
+            string nameFilter);
+
+        public bool RemoveImage(SpecificImagePathData path);
+    }
+}
diff --git a/DAL/ImagePersistence/Model/BaseImagePathData.cs b/DAL/ImagePersistence/Model/BaseImagePathData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41211c8aabee0caaf17c82a8a9bac843d5b34fe7
--- /dev/null
+++ b/DAL/ImagePersistence/Model/BaseImagePathData.cs
@@ -0,0 +1,9 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class BaseImagePathData
+    {
+        public required string OwnerEntityName { get; set; }
+        public required string OwnerEntityId { get; set; }
+        public required string ImageType { get; set; }
+    }
+}
diff --git a/DAL/ImagePersistence/Model/GenericImagePathData.cs b/DAL/ImagePersistence/Model/GenericImagePathData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f3351f6449dabd278840637668a92f47ea3fd13
--- /dev/null
+++ b/DAL/ImagePersistence/Model/GenericImagePathData.cs
@@ -0,0 +1,8 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class GenericImagePathData : BaseImagePathData
+    {
+        public required string Extension { get; set; }
+        public int? Identifier { get; set; }
+    }
+}
diff --git a/DAL/ImagePersistence/Model/ImageStorageData.cs b/DAL/ImagePersistence/Model/ImageStorageData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51adc5518255fdb8fc7913af4920436211ef5a90
--- /dev/null
+++ b/DAL/ImagePersistence/Model/ImageStorageData.cs
@@ -0,0 +1,9 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class ImageStorageData
+    {
+        public byte[] Data { get; set; } = [];
+        public required GenericImagePathData Path { get; set; }
+        public string? Mime { get; set; }
+    }
+}
diff --git a/DAL/ImagePersistence/Model/LoadedImageData.cs b/DAL/ImagePersistence/Model/LoadedImageData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..faf87786a8919903179e07cb0cc1f45b45f23147
--- /dev/null
+++ b/DAL/ImagePersistence/Model/LoadedImageData.cs
@@ -0,0 +1,9 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class LoadedImageData
+    {
+        public byte[] Data { get; set; } = [];
+        public required string Path { get; set; }
+        public string? Mime { get; set; }
+    }
+}
diff --git a/DAL/ImagePersistence/Model/RollbackEntry.cs b/DAL/ImagePersistence/Model/RollbackEntry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e06fc06977aecc305dfc3d45b687351a9b478186
--- /dev/null
+++ b/DAL/ImagePersistence/Model/RollbackEntry.cs
@@ -0,0 +1,8 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class RollbackEntry
+    {
+        public required string Path { get; set; }
+        public byte[] OriginalData { get; set; } = [];
+    }
+}
diff --git a/DAL/ImagePersistence/Model/SpecificImagePathData.cs b/DAL/ImagePersistence/Model/SpecificImagePathData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..46bbd6a81b433583bd6cb4a7ca8c7ae6584b807d
--- /dev/null
+++ b/DAL/ImagePersistence/Model/SpecificImagePathData.cs
@@ -0,0 +1,7 @@
+namespace DAL.ImagePersistence.Model
+{
+    public class SpecificImagePathData : BaseImagePathData
+    {
+        public required string Name { get; set; }
+    }
+}
diff --git a/DAL/ImagePersistence/StorageRollbackManager/IStorageRollbackManager.cs b/DAL/ImagePersistence/StorageRollbackManager/IStorageRollbackManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9dcc3585defbc6257e6f6cb54d8c334ad983c944
--- /dev/null
+++ b/DAL/ImagePersistence/StorageRollbackManager/IStorageRollbackManager.cs
@@ -0,0 +1,13 @@
+using DAL.ImagePersistence.Model;
+
+namespace DAL.ImagePersistence.StorageRollbackManager
+{
+    public interface IStorageRollbackManager
+    {
+        public void AddEntry(RollbackEntry entry);
+        public void Rollback();
+        public Task RollbackAsync();
+        public void Commit();
+        public Task CommitAsync();
+    }
+}
diff --git a/DAL/ImagePersistence/StorageRollbackManager/SimpleRollbackManager.cs b/DAL/ImagePersistence/StorageRollbackManager/SimpleRollbackManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef1483b8755a739a5c6076d641a7c0fef895de57
--- /dev/null
+++ b/DAL/ImagePersistence/StorageRollbackManager/SimpleRollbackManager.cs
@@ -0,0 +1,68 @@
+using DAL.ImagePersistence.Model;
+
+namespace DAL.ImagePersistence.StorageRollbackManager
+{
+    public class SimpleRollbackManager : IStorageRollbackManager
+    {
+        private readonly List<RollbackEntry> _rollbackEntries = [];
+
+        public SimpleRollbackManager() { }
+
+        public void AddEntry(RollbackEntry entry)
+        {
+            _rollbackEntries.Add(entry);
+        }
+
+        public void Commit()
+        {
+            _rollbackEntries.Clear();
+        }
+
+        // This is redundant, but future implementations may do something that requires async <.<
+        public Task CommitAsync()
+        {
+            _rollbackEntries.Clear();
+            return Task.CompletedTask;
+        }
+
+        public void Rollback()
+        {
+            foreach (var entry in _rollbackEntries)
+            {
+                // Checking for exceptions here is a little ... uncertain.
+                if (entry.OriginalData.Length == 0)
+                {
+                    File.Delete(entry.Path);
+                }
+                else
+                {
+                    using FileStream stream = File.Open(entry.Path, FileMode.Truncate);
+
+                    stream.Write(entry.OriginalData);
+                }
+            }
+
+            _rollbackEntries.Clear();
+        }
+
+        public async Task RollbackAsync()
+        {
+            foreach (var entry in _rollbackEntries)
+            {
+                // Checking for exceptions here is a little ... uncertain.
+                if (entry.OriginalData.Length == 0)
+                {
+                    File.Delete(entry.Path);
+                }
+                else
+                {
+                    using FileStream stream = File.Open(entry.Path, FileMode.Truncate);
+                    
+                    await stream.WriteAsync(entry.OriginalData);
+                }
+            }
+
+            _rollbackEntries.Clear();
+        }
+    }
+}
diff --git a/DAL/ImagePersistence/Utils/FileNameManager.cs b/DAL/ImagePersistence/Utils/FileNameManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..60d8b6781e7406b75339892262013f7104b769a9
--- /dev/null
+++ b/DAL/ImagePersistence/Utils/FileNameManager.cs
@@ -0,0 +1,130 @@
+using DAL.Constants;
+using DAL.ImagePersistence.Model;
+
+namespace DAL.ImagePersistence.Utils
+{
+    public static class FileNameManager
+    {
+        public static int? PrefetchExpectedIdentifier(this GenericImagePathData path, bool replace)
+        {
+            string? fullPath = path.ResolveImagePath(replace);
+
+            if (fullPath == null)
+            {
+                return null;
+            }
+
+            return fullPath.RetrieveImageIdentifier();
+        }
+
+        public static string? ResolveImagePath(this GenericImagePathData path, bool replace)
+        {
+            var genericPath = path.ComposeGenericFilePath();
+
+            if (File.Exists(genericPath) && !replace)
+            {
+                if (path.ImageType.Equals(Paths.AvatarImageName, StringComparison.InvariantCultureIgnoreCase))
+                {
+                    return null;
+                }
+
+                var name = AddIdentifierToName(genericPath);
+                var directory = Path.GetDirectoryName(genericPath);
+
+                return Path.Join(directory, name);
+            }
+
+            return genericPath;
+        }
+
+        public static string ComposeDirectoryPath(this BaseImagePathData path)
+        {
+            return Path.Combine(
+                GetRootDirectory(),
+                Paths.ImageDirPath,
+                path.OwnerEntityName,
+                path.OwnerEntityId);
+        }
+
+        public static string ComposeSpecificFilePath(this SpecificImagePathData path)
+        {
+            return Path.Combine(
+                GetRootDirectory(),
+                Paths.ImageDirPath,
+                path.OwnerEntityName,
+                path.OwnerEntityId,
+                path.Name);
+        }
+
+        /**
+         * Creates the default path for an image of a certain type.
+         * For avatar, this would be "avatar.extension", for gallery this
+         * would be "gallery.extension", etc.
+         */
+        public static string ComposeGenericFilePath(this GenericImagePathData path)
+        {
+            var identifier = path.Identifier is null || path.Identifier == 0
+                ? string.Empty
+                : Paths.ImageIdSeparator + path.Identifier;
+
+            var imageName = path.ImageType + identifier + path.Extension;
+
+            return Path.Combine(
+                GetRootDirectory(),
+                Paths.ImageDirPath,
+                path.OwnerEntityName,
+                path.OwnerEntityId,
+                imageName);
+        }
+
+        private static string GetRootDirectory()
+        {
+            return Directory
+                .GetParent(Directory.GetCurrentDirectory())!
+                .FullName;
+        }
+
+        /**
+         * Takes the generic file path for a certain image type and
+         * adds a numeric identifier into the name, giving the image
+         * its own specific name.
+         * Example: generic path - "/gallery.png"
+         *          specific path: - "/gallery-1.png"
+         */
+        public static string AddIdentifierToName(string name)
+        {
+            var extension = Path.GetExtension(name) ?? throw new ArgumentException("Provided image path has no extension.");
+            var fileName= Path.GetFileNameWithoutExtension(name);
+            var directory = Path.GetDirectoryName(name);
+
+            var count = Directory
+                .GetFiles(directory!, $"{fileName}*")
+                .Select(RetrieveImageIdentifier)
+                .Max();
+
+            return directory
+                + fileName
+                + Paths.ImageIdSeparator
+                + (++count).ToString()
+                + extension;
+        }
+
+        private static int? RetrieveImageIdentifier(this string path)
+        {
+            string name = Path.GetFileNameWithoutExtension(path);
+            string[] nameParts = name.Split(Paths.ImageIdSeparator);
+
+            if (nameParts.Length < 2)
+            {
+                return 0;
+            }
+
+            if (!int.TryParse(nameParts.Last(), out int id))
+            {
+                return null;
+            }
+
+            return id;
+        }
+    }
+}
diff --git a/DAL/ImagePersistence/Utils/ImageNameFormatException.cs b/DAL/ImagePersistence/Utils/ImageNameFormatException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9449a6f52ac0798a691f0c043f7dc6e52aded64f
--- /dev/null
+++ b/DAL/ImagePersistence/Utils/ImageNameFormatException.cs
@@ -0,0 +1,17 @@
+namespace DAL.ImagePersistence.Utils
+{
+    public class ImageNameFormatException : Exception
+    {
+        public ImageNameFormatException()
+        {
+        }
+
+        public ImageNameFormatException(string? message) : base(message)
+        {
+        }
+
+        public ImageNameFormatException(string? message, Exception? innerException) : base(message, innerException)
+        {
+        }
+    }
+}
diff --git a/pv179-project.sln b/pv179-project.sln
index fb9b03f362eee76411b522aa59b361f000a1b371..84f78eaad1756d42d086e7644bc421ef30f1f7bb 100644
--- a/pv179-project.sln
+++ b/pv179-project.sln
@@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVC", "MVC\MVC.csproj", "{1
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BusinessLayer.Tests", "BusinessLayer.Tests\BusinessLayer.Tests.csproj", "{B244DC7E-77CF-4B9A-B382-BC8E1E4B057C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "TestUtilities\TestUtilities.csproj", "{7F02D143-33B1-4A83-BE5E-8AE192DA6A8D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "TestUtilities\TestUtilities.csproj", "{DBAC81BF-6294-43DA-AA77-A293C8D03EDF}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -41,10 +41,10 @@ Global
 		{B244DC7E-77CF-4B9A-B382-BC8E1E4B057C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B244DC7E-77CF-4B9A-B382-BC8E1E4B057C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B244DC7E-77CF-4B9A-B382-BC8E1E4B057C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7F02D143-33B1-4A83-BE5E-8AE192DA6A8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7F02D143-33B1-4A83-BE5E-8AE192DA6A8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7F02D143-33B1-4A83-BE5E-8AE192DA6A8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7F02D143-33B1-4A83-BE5E-8AE192DA6A8D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DBAC81BF-6294-43DA-AA77-A293C8D03EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DBAC81BF-6294-43DA-AA77-A293C8D03EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DBAC81BF-6294-43DA-AA77-A293C8D03EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DBAC81BF-6294-43DA-AA77-A293C8D03EDF}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE