OnComplete / UploadCompleteEventArgs EventHandler not hit when returning image as Base64 from controller

I am trying to upload an image using the RadzenUpload component:

<RadzenUpload Multiple="false" Accept="image/*" Url="upload/single" Progress="@((args) => OnProgress(args, "Images only upload"))" 

                Complete=@OnComplete Error="@((args) => OnImageUploadError(args, "Image Upload Error"))" />

The controller for this looks like this, I want to get the byte array of the image to later store it in the database (when the user clicks a save button, not directly now):

public partial class ImageUploadController : Controller

    {

        [HttpPost("upload/single")]

        public async Task<IActionResult> Single(IFormFile file)

        {

            try

            {

                var fileBytes = await GetImageFileBytes(file);

                //return Ok(fileBase64);

                //return Ok(new { Completed = true, FileBase64 = fileBase64 }); // works not

                //return Ok(new { Completed = true, ImageUploaded = true }); // works

                //return Ok(new { Completed = true, FileBase64 = "test" }); // works

                return Ok("data:image/png;base64," + Convert.ToBase64String(fileBytes)); // works not

            }

            catch (Exception ex)

            {

                return StatusCode(500, ex.Message);

            }

        }...

I convert it to Base64 because returning a byte array failed but also I am unable to get the Base64 value back in the RawResponse.

The following EventHandler in my Blazor component (where also the RadzenUpload is placed) is not triggered when returning the image data as Base64 or byte array. It is triggered when I return a small test string or simply the { Completed = true } as result:

void OnComplete(UploadCompleteEventArgs args)

    {

        string x = args.RawResponse;

    }

I guess this is maybe because (even with very small images) the response is too big and this is not a recommended approach? I don't see any exceptions occuring it's just that the event handler is not getting triggered in this case.

If this is a dumb idea of doing file uploads, what would be a better approach - I don't want to write the file directly into the DB inside the controller as I would like to wait for that until the user clicks the save button on the form (but upload to server could start already, even bevor save button is pressed, so I would like to avoid setting "Auto='false'" for the RadzenUpload component if possible).

I had this problem before with a custom photo controller, which was caused by the massive length of the response string. What worked for me was returning the byte[] of the image from the server, and converting to base64 in the client:

[Route("PersonPhoto")]
[HttpGet]
public async Task<byte[]> DownloadPersonPhoto(string photoId) {
    byte[] result = null;
    try {
        result = await System.IO.File.ReadAllBytesAsync(Path.Combine(PeoplePhotosDirectory, photoId + ".jpg"));
    }
    catch (Exception exception) {
        await ErrorService.Save(exception);
    }
    return await Task.FromResult(result);
}
[Route("PersonPhoto")]
[HttpPost]
public async Task<int?> UploadPersonPhoto([FromBody] Global.Models.PersonPhoto personPhoto) {
    int? result = null;
    try {
        if (!Directory.Exists(PeoplePhotosDirectory))
            Directory.CreateDirectory(PeoplePhotosDirectory);
        var bytes = Convert.FromBase64String(personPhoto.photo.Substring(personPhoto.photo.IndexOf(",") + 1));
        using (var imageFile = new FileStream(Path.Combine(PeoplePhotosDirectory, personPhoto.photoId + ".jpg"), FileMode.Create, FileAccess.ReadWrite))
        {
            imageFile.Write(bytes, 0, bytes.Length);
            imageFile.Flush();
        }
        result = personPhoto.id;
    }
    catch (Exception exception) {
        await ErrorService.Save(exception);
    }
    return await Task.FromResult(result);
}
public async Task<string> Download<T>(string photoId) {
    return "data:image/jpeg;base64," + await HttpService.Get<string>(string.Format("{0}{1}?photoId={2}", NetworkService.GetServiceUrl(EN_Service.Front, ssl: false, port: 80), typeof(T).Name, photoId));
}
public async Task<int?> Upload<T>(T t) where T : new() {
    return await HttpService.Post<T>(string.Format("{0}{1}", NetworkService.GetServiceUrl(EN_Service.Front, ssl: false, port: 80), typeof(T).Name), t);
}

Regarding the DB load when storing files, what I did was saving a photoId that is the name of the file stored in the server.

The UploadComplete event is invoked via Blazor interop. The latter depends on SignalR to transmit the parameters. SignalR has a limitation to the maximum payload it can transmit. There is a chance you are hitting that. Our demo application is using the following code to increase the payload size:

services.AddServerSideBlazor().AddHubOptions(o =>
{
     o.MaximumReceiveMessageSize = 10 * 1024 * 1024;
});
1 Like

Thanks, that was it. I will also make sure that the image files uploaded stay under this limit, so it should be safe. Not sure about the performance for now but I will see. Suggestion by kim may come in handy, when I need to improve performance, but it's only a small test application.

This fixed my issue also. Thank you @korchev