Table of contents
Intro
In this post we will implement the profile picture upload for the ABP app using BlobStore and Minio.
Create a new project
1abp new ProfilePictureSample
Create a container
Create the container in Domain
project.
Install Volo.Abp.BlobStoring
NuGet package to your Domain
project
1[BlobContainerName("profile-picture")] 2public class ProfilePictureContainer 3{ 4}
Configure Minio
Install Volo.Abp.BlobStoring.Minio
NuGet package to your Web
and add [DependsOn(typeof(AbpBlobStoringMinioModule))]
to the Web
Module
Configuration is done in the ConfigureServices
method of your module class
1Configure<AbpBlobStoringOptions>(options => 2{ 3 options.Containers.ConfigureDefault(container => 4 { 5 container.UseMinio(minio => 6 { 7 minio.EndPoint = "localhost:9900"; // your minio endPoint 8 minio.AccessKey = "AKIAIOSFODNN7EXAMPLE"; // your minio accessKey 9 minio.SecretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; // your minio secretKey 10 minio.BucketName = "profile-picture"; // your minio bucketName 11 }); 12 }); 13});
Extend User Entity
Configure extra properties
Create the Constant file in the Domain.Shared
project.
1public static class ProfilePictureConsts 2{ 3 public const string ProfilePictureId = "ProfilePictureId"; 4}
In the Domain.Shared
project update the ProfilePictureSampleModuleExtensionConfigurator
file inside the ConfigureExtraProperties
methods with the following.
1ObjectExtensionManager.Instance.Modules() 2 .ConfigureIdentity(identity => 3 { 4 identity.ConfigureUser(user => 5 { 6 user.AddOrUpdateProperty<Guid>(ProfilePictureConsts.ProfilePictureId); 7 }); 8 });
Configure ef core
In the EntityFrameworkCore
project update the ProfilePictureSampleEfCoreEntityExtensionMappings
file inside the Configure
method. Update the OneTimeRunner.Run
with the following
1ObjectExtensionManager.Instance 2 .MapEfCoreProperty<IdentityUser, Guid>(ProfilePictureConsts.ProfilePictureId);
Add Migrations
Navigate to the EntityFrameworkCore
.
1cd .\src\ProfilePictureSample.EntityFrameworkCore\
Add migrations
1dotnet ef migrations add "update_user"
Apply the migrations
1dotnet ef database update
Create the AppService
Create a AppService to upload and view the profile picture.
1[Authorize] 2public class ProfilePictureAppService : ProfilePictureSampleAppService 3{ 4 private readonly IBlobContainer<ProfilePictureContainer> _blobContainer; 5 private readonly IRepository<IdentityUser, Guid> _repository; 6 7 public ProfilePictureAppService(IBlobContainer<ProfilePictureContainer> blobContainer, IRepository<IdentityUser, Guid> repository) 8 { 9 _blobContainer = blobContainer; 10 _repository = repository; 11 } 12 13 public virtual async Task<Guid> UploadAsync(IFormFile file) 14 { 15 await using var memoryStream = new MemoryStream(); 16 await file.CopyToAsync(memoryStream).ConfigureAwait(false); 17 if (CurrentUser.Id == null) 18 { 19 return Guid.Empty; 20 } 21 22 var user = await _repository.GetAsync(CurrentUser.Id.Value).ConfigureAwait(false); 23 var pictureId = user.GetProperty<Guid>(ProfilePictureConsts.ProfilePictureId); 24 25 if (pictureId == Guid.Empty) 26 { 27 pictureId = Guid.NewGuid(); 28 } 29 var id = pictureId.ToString(); 30 if (await _blobContainer.ExistsAsync(id).ConfigureAwait(false)) 31 { 32 await _blobContainer.DeleteAsync(id).ConfigureAwait(false); 33 } 34 await _blobContainer.SaveAsync(id, memoryStream.ToArray()).ConfigureAwait(false); 35 user.SetProperty(ProfilePictureConsts.ProfilePictureId, pictureId); 36 await _repository.UpdateAsync(user).ConfigureAwait(false); 37 return pictureId; 38 } 39 40 public async Task<FileResult> GetAsync() 41 { 42 if (CurrentUser.Id == null) 43 { 44 throw new FileNotFoundException(); 45 } 46 47 var user = await _repository.GetAsync(CurrentUser.Id.Value).ConfigureAwait(false); 48 var pictureId = user.GetProperty<Guid>(ProfilePictureConsts.ProfilePictureId); 49 if (pictureId == default) 50 { 51 throw new FileNotFoundException(); 52 } 53 54 var profilePicture = await _blobContainer.GetAllBytesOrNullAsync(pictureId.ToString()).ConfigureAwait(false); 55 return new FileContentResult(profilePicture, "image/jpeg"); 56 57 } 58}