Code Monkey home page Code Monkey logo

Comments (5)

abdullahshaqaliah avatar abdullahshaqaliah commented on June 10, 2024 1

Yes, thank you

from abp.

maliming avatar maliming commented on June 10, 2024

hi

Try to make your GetForSaveEditAsync method virtual.

Can you also share the code of EraTech.StorageService.AttachmentAppService1.UploadAsync(UploadInputDto input)

from abp.

abdullahshaqaliah avatar abdullahshaqaliah commented on June 10, 2024

Hi
I found the problem with my code

public virtual async Task CommitUploadsAsync()
    {
        if (_files.Any())
        {
            await Task.WhenAll(_files).ConfigureAwait(false);
        }
    }
Because this a layer application I used to auto-upload any attachment files with the view model and save the file information in the database and this is my code before for attachments
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using EraTech.AspNetCore.Mvc.UI.Attributes;
using EraTech.AspNetCore.Mvc.UI.Theme.Shared.Models;
using EraTech.StorageService;
using EraTech.StorageService.FileManagers;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Users;

namespace EraTech.AspNetCore.Mvc.UI;
public class UploaderManager : IUploaderManager, ITransientDependency
{

    private readonly IFileManagerAppService _fileManagerAppService ;
    private readonly ICurrentUser _currentUser;
    private readonly IGuidGenerator _guidGenerator;

    private List<Task<FileDto>> _files;


    public UploaderManager(IFileManagerAppService fileManagerAppService, ICurrentUser currentUser, IGuidGenerator guidGenerator)
    {
        _fileManagerAppService = fileManagerAppService;
        _currentUser = currentUser;
        _files = new List<Task<FileDto>>();
        _guidGenerator = guidGenerator;
    }

    public async Task StartUploadsAsync(object model)
    {
        await AddFromStorageAttributeAsync(model).ConfigureAwait(false);
        await AddFromImageListAsync(model).ConfigureAwait(false);
        
    }

    public virtual async Task CommitUploadsAsync()
    {
        if (_files.Any())
        {
            await Task.WhenAll(_files).ConfigureAwait(false);
        }
    }

    public virtual async Task<FileDto> UploadFileAsync(IFormFile file, Guid? id = default)
    {
        if (file == null) { return new(); }
        using (var memoryStream = new MemoryStream())
        {
            await file.CopyToAsync(memoryStream);

            var attachment = await _fileManagerAppService.UploadAsync(
                 new UploadInputDto
                 {
                     AttachmentId = id,
                     Name = file.FileName,
                     UserId = _currentUser.GetId(),
                     ContentType = file.ContentType,
                     Content = memoryStream.ToArray()
                 }
             );
            return attachment;
        }
    }

    public Task AddFileAsync(IFormFile file, Guid? id = null)
    {
        _files.Add(UploadFileAsync(file, id));

        return Task.CompletedTask;
    }

    public async Task<List<Task<FileDto>>> GetFilesAsync()
    {
        return await Task.FromResult(_files);
    }

    protected virtual async Task AddFromStorageAttributeAsync(object model)
    {
        var props = model.GetType().GetProperties().Where(
           prop => Attribute.IsDefined(prop, typeof(StorageAttribute))).ToList();

        if (!props.IsNullOrEmpty())
        {

            foreach (var prop in props)
            {
                IFormFile file = prop.GetValue(model).As<IFormFile>();
                if (file != null)
                {
                    var storageAttr = prop.GetCustomAttribute<StorageAttribute>();
                    var storageId = _guidGenerator.Create();

                    var storageIdProp = model.GetType().GetProperty(storageAttr.OtherPropertyStorageId);

                    storageIdProp.SetValue(model, storageId);

                    if (!storageAttr.OtherPropertyStorageFileName.IsNullOrEmpty())
                    {
                        var fileNameProp = model.GetType().GetProperty(storageAttr.OtherPropertyStorageFileName);
                        fileNameProp.SetValue(model, file.FileName);
                    }
                    _files.Add(UploadFileAsync(file, storageId));
                }
            }
        }
        await Task.CompletedTask;
    }

    protected virtual async Task AddFromImageListAsync(object model)
    {
        var props = model.GetType().GetProperties().Where(prop => prop.PropertyType == typeof(List<ImageTranslationItem>)).ToList();
        if (!props.IsNullOrEmpty())
        {
            foreach (var prop in props)
            {
                var files = prop.GetValue(model).As<List<ImageTranslationItem>>();
                if (files.IsNullOrEmpty())
                    continue;
                foreach (var file in files.Where(x => x.Content != null))
                {
                    file.StorageId = _guidGenerator.Create();
                    _files.Add(UploadFileAsync(file.Content, file.StorageId));
                }
                files.RemoveAll(x => (x.Removed == 1 && x.Content == null) || !x.StorageId.HasValue);
            }

        }
        await Task.CompletedTask;
    }


}

and my view model code

public class UpdateViewModel
{
    [HiddenInput]
    public Guid Id { get; set; }
    [HiddenInput]
    public decimal Version { get; set; }

    [HiddenInput]
    public Guid? ImageId { get; set; }
    
    [FileUploadExtensions]
    
    [FileUploadSize()]
    
    [Image(nameof(ImageId), ContainerHeight = 125, ContainerWidth = 125, Style = MetronicImageInputStyle.Outline)]
   
    [Storage(nameof(ImageId))]
    [Display(Name = "Logo")]
    public IFormFile Image {  get; set; }

    [Required]
    [StringLength(InitiativeConsts.MaxNameLength, MinimumLength = InitiativeConsts.MinNameLength)]
    [Display(Name = "VersionName")]
    [Css("form-control-solid")]

    public string DisplayName { get; set; }

    [StringLength(InitiativeConsts.MaxDescriptionLength, MinimumLength = InitiativeConsts.MinDescriptionLength)]
    [TextArea]
    [Css("form-control-solid h-100px")]
    public string Description { get; set; }


    [Display(Name ="Project")]
    [Select2]
    [SelectItems(nameof(Projects))]
    [Required]
    [Css("form-control-solid")]
    [ContainerCSS("col-6")]
    public Guid? ProjectId { get; set; }
    [Label]
    [ContainerCSS("col-6 mt-2")]
    public string StrategicGoal { get; set; }

    [Display(Name = "Category")]
    [Select2]
    [SelectItems(nameof(Categories))]
    [Required]
    [Css("form-control-solid")]
    [ContainerCSS("col-6")]
    public Guid? CategoryId { get; set; }
    [Display(Name = "TargetGroup")]
    [Select2]
    [SelectItems(nameof(Groups))]
    [Required]
    [Css("form-control-solid")]
    [ContainerCSS("col-6")]

    public Guid? UserTypeId { get; set; }
    [Display(Name ="Leader")]
    [Required]
    [Select2("/api/sm/data-lookup/users",dataTextField:"text", template: "Select2UserFormat")]
    [SelectItems(nameof(Leader))]
    [Css("form-control-solid")]
    [ContainerCSS("col-6")]

    public Guid? LeaderId { get; set; }

    [Display(Name = "Priority")]
    [Select2]
    [SelectItems(nameof(Orders))]
    [Required]
    [Css("form-control-solid")]
    [ContainerCSS("col-6")]

    public int DisplayOrder { get; set; }

    [StringLength(InitiativeConsts.MaxDescriptionLength, MinimumLength = InitiativeConsts.MinDescriptionLength)]
    [TextArea]
    [Css("form-control-solid h-100px")]
    public string LessonsLearned { get; set; }
}

The storage attribute code

using System;
namespace EraTech.AspNetCore.Mvc.UI.Attributes;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class StorageAttribute : Attribute
{
    public string OtherPropertyStorageId { get; set; }

    public string OtherPropertyStorageFileName { get; set; }

    public StorageAttribute(string otherPropertyStorageId)
    {
        OtherPropertyStorageId = otherPropertyStorageId;
    }

    public StorageAttribute(string otherPropertyStorageId, string otherPropertyStorageFileName)
    {
        OtherPropertyStorageId = otherPropertyStorageId;
        OtherPropertyStorageFileName = otherPropertyStorageFileName;
    }
}

There are attributes I make as custom to help me with low-code development

from abp.

abdullahshaqaliah avatar abdullahshaqaliah commented on June 10, 2024

My code for auto development page model for create or update

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace EraTech.AspNetCore.Mvc.UI;
public abstract class EraTechCreateOrUpdateBasePageModel<TService, TOutput, TKey, TViewModel> : EraTechPageModel
     where TService : IApplicationService
{
    protected TService AppService => LazyServiceProvider.LazyGetRequiredService<TService>();

    [BindProperty(SupportsGet = true)]
    public TKey Id { get; set; }

    [BindProperty()]
    public TViewModel Info { get; set; }

    public TOutput OutputDto { get; set; }



    protected bool CheckkeyHasValue()
    {
        return !EqualityComparer<TKey>.Default.Equals(Id, default);
    }

    /// <summary>
    /// Call after OnGet method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnGetExecutedAsync()
    {
        await Task.CompletedTask;
    }
    /// <summary>
    /// Call before OnGet method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnGetExecutingAsync()
    {
        await Task.CompletedTask;
    }
    /// <summary>
    /// Call after OnPost method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnPostExecutedAsync()
    {
        await Task.CompletedTask;
    }
    /// <summary>
    /// Call before OnPost method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnPostExecutingAsync()
    {
        await Task.CompletedTask;
    }

    /// <summary>
    /// Call Before OnPost method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnUploadExecutingAsync()
    {

        await UploaderManager.StartUploadsAsync(Info).ConfigureAwait(false);
    }

    /// <summary>
    /// Call after OnPost method executes
    /// </summary>
    /// <returns></returns>
    protected virtual async Task OnUploadExecutedAsync()
    {
        await UploaderManager.CommitUploadsAsync();

    }

}
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace EraTech.AspNetCore.Mvc.UI;


public abstract class EraTechCreateOrUpdatePageModel<TService, TOutput, TKey, TViewModel> : 
    EraTechCreateOrUpdateBasePageModel<TService, TOutput, TKey, TViewModel>
     where TService : IApplicationService
{
    protected async Task<TOutput> CreateAsync<TCreateService, TCreateInput>() where TCreateService : ICreateAppService<TOutput, TCreateInput>
    {
        var service = LazyServiceProvider.GetRequiredService<TCreateService>();
        await OnUploadExecutingAsync().ConfigureAwait(false);
        var createDto = ObjectMapper.Map<TViewModel, TCreateInput>(Info);
        OutputDto = await service.CreateAsync(createDto).ConfigureAwait(false);
        await OnUploadExecutedAsync().ConfigureAwait(false);

        return OutputDto;
    }

    protected async Task<TOutput> UpdateAsync<TUpdateService, TUpdateInput>() where TUpdateService : IUpdateAppService<TOutput, TKey, TUpdateInput>
    {
        var service = LazyServiceProvider.GetRequiredService<TUpdateService>();
        await OnUploadExecutingAsync().ConfigureAwait(false);
        var updateDto = ObjectMapper.Map<TViewModel, TUpdateInput>(Info);
        OutputDto = await service.UpdateAsync(Id, updateDto).ConfigureAwait(false);
        await OnUploadExecutedAsync().ConfigureAwait(false);
        return OutputDto;
    }


}

public abstract class EraTechCreateOrUpdatePageModel<TEntityDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput, TService, TViewModel> :
    EraTechCreateOrUpdatePageModel<TService, TEntityDto, TKey, TViewModel>
    where TService : ICrudAppService<TEntityDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
    where TViewModel : class


{
    public virtual async Task OnGetAsync()
    {
        await OnGetExecutingAsync().ConfigureAwait(false);

        if (CheckkeyHasValue())
        {
            OutputDto = await AppService.GetAsync(Id).ConfigureAwait(false);
            Info = ObjectMapper.Map<TEntityDto, TViewModel>(OutputDto);
        }
        await OnGetExecutedAsync().ConfigureAwait(false);

    }

    public virtual async Task<IActionResult> OnPostAsync()
    {
        await OnPostExecutingAsync().ConfigureAwait(false);

        ValidateModel(Info);

        if (CheckkeyHasValue())
        {
            OutputDto = await UpdateAsync<TService, TUpdateInput>().ConfigureAwait(false);
        }
        else
        {
            OutputDto = await CreateAsync<TService,TCreateInput>().ConfigureAwait(false);

        }
        await OnPostExecutedAsync().ConfigureAwait(false);

        return new OkObjectResult(OutputDto);
    }

}

public class EraTechCreateOrUpdatePageModel<TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput, TService, TViewModel> :
    EraTechCreateOrUpdatePageModel<TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput, TService, TViewModel>
    where TService :
    ICrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>

    where TViewModel : class
{

}

public class EraTechCreateOrUpdatePageModel<TEntityDto, TKey, TGetListInput, TCreateOrUpdateInput, TService, TViewModel> :
EraTechCreateOrUpdatePageModel<TEntityDto, TKey, TGetListInput, TCreateOrUpdateInput, TCreateOrUpdateInput, TService, TViewModel>
where TService : ICrudAppService<TEntityDto, TKey, TGetListInput, TCreateOrUpdateInput>

where TViewModel : class
{

}

public class EraTechCreateOrUpdatePageModel<TEntityDto, TKey, TGetListInput, TService, TViewModel> :
    EraTechCreateOrUpdatePageModel<TEntityDto, TKey, TGetListInput, TEntityDto, TService, TViewModel>
    where TService : ICrudAppService<TEntityDto, TKey, TGetListInput>

    where TViewModel : class
{

}

Example

public class EditModalModel : EraTechCreateOrUpdatePageModel<SupportPhoneNumberDto, SupportPhoneNumberListDto, Guid, GetSupportPhoneNumberInput, SupportPhoneNumberCreateOrUpdateDto, SupportPhoneNumberCreateOrUpdateDto, ISupportPhoneNumberAppService, SupportPhoneNumberViewModel>
{
    private IDataLookupRemoteService _dataLookupRemoteService => LazyServiceProvider.LazyGetRequiredService<IDataLookupRemoteService>();
    public List<SelectListItem> CountriesList { get; set; }
    protected override async Task OnGetExecutingAsync()
    {
        var countriesList = await _dataLookupRemoteService.GetCountiresListAsync();
        CountriesList = countriesList.OrderBy(x => x.Name)
            .Select(x => new SelectListItem(x.Name, x.Id.ToString()))
            .ToList();

        CountriesList.Insert(0,new SelectListItem("",""));
    }

    protected override  Task OnPostExecutingAsync()
    {
        Info.CountryPhoneNumbers = new List<CountryPhoneNumberDto>();

        Info.CountryPhoneNumbers.Add(new CountryPhoneNumberDto(Info.FirstPhoneNumber));
        if (!Info.IsGlobal && !Info.SecondPhoneNumber.IsNullOrEmpty())
        {
            Info.CountryPhoneNumbers.Add(new CountryPhoneNumberDto(Info.SecondPhoneNumber));

        }
        
        return Task.CompletedTask;
    }

    [AutoMap(typeof(SupportPhoneNumberDto))]
    [AutoMap(typeof(SupportPhoneNumberCreateOrUpdateDto), ReverseMap = true)]

    public class SupportPhoneNumberViewModel : IValidatableObject
    {
        [HiddenInput]
        public Guid Id { get; set; }
        [Display(Name = "FormName:IsGlobal")]
        public bool IsGlobal { get; set; }

        [Display(Name = "FormName:Country")]
        [Required]
        [SelectItems(nameof(CountriesList))] 
        [Css("select2_country")] 
        public int? CountryId { get; set; }
        [Display(Name = "FormName:FirstPhoneNumber")]
        [Required]
        [StringLength(maximumLength: SupportPhoneNumberConsts.MaxPhoneLength, MinimumLength = SupportPhoneNumberConsts.MinPhoneLength)]
        public string FirstPhoneNumber { get; set; }

        [StringLength(maximumLength: SupportPhoneNumberConsts.MaxPhoneLength, MinimumLength = SupportPhoneNumberConsts.MinPhoneLength)]
        [Display(Name = "FormName:SecondPhoneNumber")]
        [ContainerCSSIf(nameof(ShowSecondPhoneNumber),"second-number", "second-number d-done")]
        public string SecondPhoneNumber { get; set; }

        [HiddenInput]
        public Guid? FlagId { get; set; }
        
        [FileUploadExtensions]
        
        [FileUploadSize()]
        
        [Image(nameof(ImageId), ContainerHeight = 125, ContainerWidth = 125, Style = MetronicImageInputStyle.Outline)]
       
        [Storage(nameof(FlagId))]
        [Display(Name = "Logo")]
        public IFormFile Flag{  get; set; }
        [DynamicFormIgnore]
        public List<CountryPhoneNumberDto> CountryPhoneNumbers { get; set; }


        public bool ShowSecondPhoneNumber()
        {
            return !IsGlobal;
        }
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var l = validationContext.GetRequiredService<IStringLocalizer<CMSServiceResource>>();
            if (FirstPhoneNumber.Equals(SecondPhoneNumber, StringComparison.OrdinalIgnoreCase))
            {
                yield return new ValidationResult(string.Format(l[CMSServiceDomainErrorCodes.SupporthoneNumbers.Validation.EqualFirstAndSecondPhoneNumber]));
            }

        }
    }

}


from abp.

maliming avatar maliming commented on June 10, 2024

Great, Is your problem solved?

from abp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.