Hello all,
I am trying to implement Kendo Upload in my project. Project is at Angular 4.4.6 version. We are having difficulty understanding and finding an example which shows how you send an attachment with a true web service call.
Can you please post an example which shows an example with a true web service call to upload an attachment.
Thanks,
Akshay
1 Answer, 1 is accepted
We don't have such example available, however any of the examples in our documentation would work with a web service, as the files are uploaded as standard multipart form-data. No Upload specific configuration would be needed.
Regards,
Dimiter Madjarov
Progress Telerik
The kendo-upload with [autoUpload]="false" shows a 'Clear' and 'Upload' button after selecting a file. Is there a way to associate a click event to the 'Upload' button, so I can add code to call a typescript service (which encapsulates the API endpoint) ?
Thanks!
Yes, a callback could be executed when the "Upload" button is clicked. To achieve this attach a handler to the upload event of the component
https://www.telerik.com/kendo-angular-ui-develop/components/upload/api/UploadComponent/#toc-upload
Another approach to achieve this task (since the end point should be invoked manually) would be to use an HttpInterceptor to catch the request and insert custom logic before the actual request is initiated.
https://angular.io/api/common/http/HttpInterceptor
Our demos use similar approach to prevent the actual upload process of the files
https://www.telerik.com/kendo-angular-ui-develop/components/upload/
Regards,
Dimiter Madjarov
Progress Telerik
Thanks Dimiter for your quick reply.
I am trying to POST a form-data content-type to my Web Api Controller but on the server, there is no file data attached to the request. Would you have some sample code to show how to post a form-data to the server? I am not sure if I should set content-type to 'multipart/formdata' in the POST request?
Here's is my kendo-upload control definition (note that I removed the [saveUrl] and [removeUrl], since I am using Upload event handler to manually call my upload controller, is that OK?)
<kendo-upload
[autoUpload]="false"
[restrictions]="uploadRestrictions"
(select)="selectEventHandler($event)"
(clear)="clearEventHandler($event)"
(remove)="removeEventHandler($event)"
(complete)="completeEventHandler($event)"
(upload)="uploadEventHandler($event)">
</kendo-upload>
in my .ts file, the selectEventHandler function is setting the property currentFileUpload:
public selectEventHandler(e: SelectEvent): void {
const that = this;
e.files.forEach((file) => {
console.log(`File selected: ${file.name}`);
if (!file.validationErrors) {
this.currentFileUpload = file;
}
});
the uploadEventHandler function is calling my fileservice method UploadFile():
uploadEventHandler(e: UploadEvent) {
// alert('file uploaded=' + e.files[0].name);
this.fileservice.isLoading = true;
this.fileservice.uploadFile(this.currentFileUpload);
}
My fileservice.service.ts has a function uploadFile and constructor as:
constructor(private httpclient: HttpClient) {
}
uploadFile(file: File): any {
const formdata: FormData = new FormData();
formdata.append('file', file); //the uploaded file content
formdata.append('documentVersionId', '123'); //I need to pass some additional info to the server besides the File data
const apiURL = this.api_path + 'Upload'; //calling http://localhost:52333/api/UploadController
const uploadReq = new HttpRequest('POST', apiURL, formdata, {
reportProgress: true
});
this.httpclient.request(uploadReq).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
}
});
}
On the server side, the api controller class POST method does not get any file data in the HttpContext.Current.Request, ie. httpRequest.Files.Count = 0.
If I checked HttpContext.Current.Request.Form in debug window, I saw two keys: file and documentVersionId.
public class UploadController : ApiController
{
[HttpPost]
public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0) // ==> THERE IS NO FILE attached here
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
It looks like that in the current implementation, the whole file information (i.e. size, extension, validation errors etc.) is passed to the custom upload service. It is wrapped in a FileInfo interface
https://www.telerik.com/kendo-angular-ui/components/upload/api/FileInfo/
The specific file data is contained in the rawFile property, which is the actual file that should be uploaded.
As for the server side implementation, there is no Kendo UI specific implementation that is required, different than parsing a regular FormData request.
Regards,
Dimiter Madjarov
Progress Telerik
Thanks Dimiter about the rawFile property info.
I got my upload to work as expected.
Here's my sample code if anyone is interested:
On the client side: the uploadEventHandler is passing a Set<File> to the WebAPI controller on the server.
uploadEventHandler(e: UploadEvent) {
this.kendoFiles = e.files;
this.filesSet = new Set<File>();
for (let i = 0; i < this.kendoFiles.length; i++) {
const rawFile: File = this.kendoFiles[i].rawFile;
this.filesSet.add(rawFile);
}
this.fileservice.isLoading = true;
var documentversionid = "123";
this.fileservice.uploadFile(this._filesSet, documentversionid);
}
In fileservice.service.ts: function uploadFile sends a POST request to the WebAPI Controller
uploadFile(filesSet: Set<File>, documentversionid: string) {
filesSet.forEach(file => {
// create a new multipart-form for every file
const formdata: FormData = new FormData();
formdata.append('file', file);
formdata.append('filetype_for_upload', documentversionid);
// create a http-post request and pass the form
// tell it to report the upload progress
const apiURL = this.api_path + 'Upload';
const uploadReq = new HttpRequest('POST', apiURL, formdata, {
reportProgress: true,
responseType: 'text'
}
);
this.httpclient.request(uploadReq).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
}
});
});
}
WebAPI Controller code:
public class UploadController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Post()
{
try
{
//read file and save to disk
var uploadpath = ConfigurationManager.AppSettings["upload"];
DirectoryInfo di = Directory.CreateDirectory(uploadpath); //physical file path location to save uploaded file
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
var documentversionid= httpRequest.Form["documentversionid"]; //get the value passed from client
//to get file content
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var outfilePath = Path.Combine(uploadpath, postedFile.FileName);
if (File.Exists(outfilePath))
File.Delete(outfilePath);
postedFile.SaveAs(outfilePath);
docfiles.Add(outfilePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse<Exception>(HttpStatusCode.InternalServerError, ex);
}
}
}
Note: The kendo-upload HTML still needs to have [saveUrl] property defined. (even though my updateEventHandler function already posted the file request to the WebAPI controller). Set the saveUrl value to the same url used to make the POST request to WebApi controller (to avoid seeing the error 'Not found' during the file upload), or add code to intercept the redundant second request to NOT POST to server caused by setting a value in [saveUrl].
<kendo-upload
[autoUpload]="false"
[saveUrl]="uploadSaveUrl"
[restrictions]="uploadRestrictions"
(select)="selectEventHandler($event)"
(clear)="clearEventHandler($event)"
(remove)="removeEventHandler($event)"
(complete)="completeEventHandler($event)"
(upload)="uploadEventHandler($event)" >
</kendo-upload>
We are glad to understand that the provided information proved useful. Thank you for sharing your solution with the community.
Regards,
Dimiter Topalov
Progress Telerik
Hi Dimiter,
I'd like to know if it's possible to customize the kendo-upload component to modify:
a) the area with the upload progress check mark and label 'Done': It looks like currently this is handled (by default) using the saveUrl property, if the saveUrl POST request is not found, then the upload progress icon is shown with an exclamation.
b) the color of the uploaded file: if the saveUrl property POST request returns an HttpStatus.OK, the color will be green, otherwise red.
In my app, I have an HttpInterceptor to catch the saveUrl and prevent it to send a redundant request to server, so I return a HttpStatus.OK there.
I have custom code in the UploadEventHandler calling WebAPI Controller, which can return an exception due to business logic, and I am looking for ways to set the uploaded file color to red, and also set the upload progress icon to be an exclamation with a label 'Error importing file'.
Please check my answer in the other thread on the same topic. I think it also covers this question. Let me know if I am missing something here.
For simplicity lets keep the conversation going in one of those threads.
Regards,
Dimiter Madjarov
Progress Telerik