This is a migrated thread and some comments may be shown as answers.

Sample of uploading to S3 with progress indicator

1 Answer 1754 Views
Upload
This is a migrated thread and some comments may be shown as answers.
n/a
Top achievements
Rank 1
n/a asked on 18 Aug 2019, 04:17 PM

I am unclear how the kendo upload communicates with the server to get the progress indicator.  In my application the progress indicator always goes from directly from 0% to complete regardless of file size.   I have the S3Helper on the server logging status but I don't know how to make that status known to the client.

Upload Service

using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Threading.Tasks;
using ARLNService.Helpers;
using ARLNService.Models;
using ARLNService.Services;
using System;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using System.IO;
using OfficeOpenXml;
using System.Linq;
using System.Data.SqlClient;
 
namespace ARLNService.Controllers
{
    [EnableCors("MyPolicy")]
    [ApiController]
    [ApiVersionNeutral]
    [Route("api/[controller]/[action]")]
    public class UploadFilesController : Controller
    {
        private readonly IConfiguration _configuration;
        private readonly ARLNServiceContext _db;
 
 
        public UploadFilesController(
               IConfiguration configuration,
                    ARLNServiceContext db)
        {
            _configuration = configuration;
            _db = db;
        }
 
        [HttpPost]
        public async Task<IActionResult> UploadFile(IList<IFormFile> files)
        {
         
            String bucket = _configuration["AWS:bucket"];
            String accessKey = _configuration["AWS:AWS_ACCESS_KEY_ID"];
 
            System.DateTime thisDay = System.DateTime.Now;
 
            // I'm getting file inside Request object
            var file = this.Request.Form.Files[0];
 
            // create unique file name for prevent the mess
            var fileName = Guid.NewGuid() + file.FileName;
 
            string userName = this.Request.Form["userName"].ToString();
 
            Upload upload = new Upload();
            upload.fileName = fileName;
            upload.uploadDate = thisDay;
            upload.userName = userName;
            upload.originalFileName = file.FileName;
            _db.Set<Upload>().Add(upload);
            _db.SaveChanges();
 
            var fileResponse =  await S3Service.UploadObject(file, fileName, bucket, fileName, userName);
 
            Upload uploadUpdate = _db.Uploads.FirstOrDefault(c => c.fileName == fileName);
 
 
            if (fileResponse.success == true)
            {
                uploadUpdate.uploadStatus = "Uploaded";
                _db.SaveChanges();
                return Ok();
            }
            else
            {
                uploadUpdate.uploadStatus = "Upload Failed";
                _db.SaveChanges();
                return BadRequest("Failed to upload file");
            }
 
        }
 
    }
}

 

Helper function for S3

using System;
using System.IO;
using System.Threading.Tasks;
using Amazon.S3;
using Amazon.S3.Model;
using ARLNService.Models;
 
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Mvc;
using Amazon.S3.Transfer;
 
namespace ARLNService.Helpers
{
    public class S3Service
    {
 
 
        public async static Task<UploadFile> UploadObject(IFormFile file, String fileName, String bucket,  String accessKey, String userName)
        {
            // connecting to the client
            var client = new AmazonS3Client();
             
 
            // get the file and convert it to the byte[]
            byte[] fileBytes = new Byte[file.Length];
            file.OpenReadStream().Read(fileBytes, 0, Int32.Parse(file.Length.ToString()));
 
 
 
            try
            {
                using (System.IO.MemoryStream filestream = new System.IO.MemoryStream(fileBytes))
                {
 
                    using (Amazon.S3.Transfer.TransferUtility tranUtility =
                      new Amazon.S3.Transfer.TransferUtility(client))
                    {
 
                        var request = new TransferUtilityUploadRequest
                        {
                            BucketName = bucket,
                            Key = accessKey,
                            InputStream = filestream
                        };
 
                        request.Metadata.Add("userName", userName);
 
                        request.UploadProgressEvent += new EventHandler<UploadProgressArgs> (uploadRequest_UploadPartProgressEvent);
 
                        await tranUtility.UploadAsync(request);
 
                     }
                }
 
                return new UploadFile
                {
                    success = true,
                    fileName = fileName
                };
            }
            catch (Exception e)
            {
                return new UploadFile
                {
                    success = false,
                    fileName = fileName
                };
            }
        }
 
        static void uploadRequest_UploadPartProgressEvent(object sender, UploadProgressArgs e)
        {
            // Process event.
            Console.WriteLine("{0}/{1}", e.TransferredBytes, e.TotalBytes);
        }
    }
}

 

Angular Component

<div class="filters    " (click)="activate()">
 
  <div class="confirmMessage">
    <p>Choose select file to upload a .csv file.</p>
  </div>
  <div class="dropdownSection">
 
    <kendo-upload #myUpload="kendoUpload" [saveUrl]="uploadSaveUrl"
                  (upload)="uploadEventHandler($event)"
                  (success)="loadItems($event)"
                  [removeUrl]="uploadRemoveUrl"
                  [restrictions]="myRestrictions"
                   [multiple]="false"
                  [accept]="acceptString">
      <kendo-upload-messages select="Select file...">
      </kendo-upload-messages>
    </kendo-upload>
    <br />
 
  </div>
</div>
<div class="clearfix"></div>

 

Angular code

import { Component, OnDestroy, OnInit, Output, EventEmitter, ChangeDetectorRef, Injector, ViewEncapsulation } from '@angular/core';
import { FormControl } from "@angular/forms";
import { Subscription } from 'rxjs/Subscription';
import { IPageInfo, IMetadata, IEntry, IRootObject } from '../../models/eipMessage';
import { DataService } from '../../shared/data.services';
import { UtilService } from '../../shared/util.service';
import { UtilityService } from '../../shared/utility.service';
 
import { ErrorMessageService } from '../../shared/error-message.service';
import { GlobalService } from '../../shared/global.service';
import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material';
import * as _ from 'lodash';
import { FileRestrictions, UploadEvent, FileState } from '@progress/kendo-angular-upload';
import { environment } from '../../../environments/environment';
import { Observable, of, concat } from 'rxjs';
import { delay } from 'rxjs/operators';
 
@Component({
  selector: 'uploads-file-select',
  templateUrl: 'uploads-file-select.component.html',
  styleUrls: ['uploads-file-select.component.scss']
})
export class UploadsFileSelectComponent implements OnInit, OnDestroy {
 
  public acceptString = ".txt, .csv";
  public uploadSaveUrl = environment.serviceUrl + "api/UploadFiles/UploadFile"; // should represent an actual API endpoint
  myRestrictions: FileRestrictions = {
    allowedExtensions: ['.csv', '.txt']
  };
 
  @Output() fileUploaded = new EventEmitter();
 
  constructor(private utilityService: UtilityService,  private dataService: DataService, private errMsgService: ErrorMessageService,
    private injector: Injector, private changeRef: ChangeDetectorRef,
    private utilService: UtilService, private globalService: GlobalService) {
  }
 
   
  uploadEventHandler(e: UploadEvent) {
    e.data = {
      userName: "tester@lab.com"
    };
  }
 
  public remove(upload, uid: string) {
    console.log("remove" + uid);
    upload.removeFilesByUid(uid);
  }
 
  public loadItems(event) {
    console.log("load itemas");
    this.fileUploaded.emit();
  }
 
  ngOnInit() {
 
  }
 
  ngOnDestroy() {
 
  }
 
  activate() {
 
  };
 
}

 

 

1 Answer, 1 is accepted

Sort by
0
Accepted
T. Tsonev
Telerik team
answered on 21 Aug 2019, 06:59 AM
Hello John,

Please, accept my apologies for the delayed response.

The Upload reports the status of the upstream request to the server. Once the data is transmitted, the progress bar will remain at 100% until a response is received.

There is no built-in mechanism for reporting the progress of server-side operations, for example uploading the data to S3.
That said, such feature might be beneficial to a wide group of users. We'd appreciate it if you cast your vote for it so we can prioritize accordingly.

One idea to implement this scenario with the current features is to use the file template to display an additional progress indicator for the S3 upload.
This indicator would have to receive status information from a separate server end-point.

Best Regards,
T. Tsonev
Progress Telerik
Get quickly onboarded and successful with your Telerik and Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Tags
Upload
Asked by
n/a
Top achievements
Rank 1
Answers by
T. Tsonev
Telerik team
Share this question
or