如何使用kendo fileselect将angular应用程序上传到C#web API?

如何使用kendo fileselect将angular应用程序上传到C#web API?,angular,file-upload,kendo-ui,asp.net-core-webapi,Angular,File Upload,Kendo Ui,Asp.net Core Webapi,我们正在我们的项目中为angular实现剑道。我们有一个现有的项目,正在使用剑道上传,它会立即激发对服务器的调用,但我不能为这个页面这样做 该页面供员工上传简历。他们可能有一份现有的简历,需要先询问他们是否要替换,然后会给他们一个字段以输入描述。因此,我认为我需要使用kendo fileselect并可能触发一个对话框(您确定要替换吗?),然后单击按钮发送描述和员工ID。所以我创建了一个对象来携带这些数据 您可以看到,对象在调用API时被填充: 但是当我尝试调用API方法时,我得到一个错误:

我们正在我们的项目中为angular实现剑道。我们有一个现有的项目,正在使用剑道上传,它会立即激发对服务器的调用,但我不能为这个页面这样做

该页面供员工上传简历。他们可能有一份现有的简历,需要先询问他们是否要替换,然后会给他们一个字段以输入描述。因此,我认为我需要使用kendo fileselect并可能触发一个对话框(您确定要替换吗?),然后单击按钮发送描述和员工ID。所以我创建了一个对象来携带这些数据

您可以看到,对象在调用API时被填充:

但是当我尝试调用API方法时,我得到一个错误:

Failed to load resource: the server responded with a status of 400 (Bad Request) [http://localhost:6300/api/employee/resume]

相关代码如下

服务器端:

public class EmployeeResume
{
    public int ResumeId { get; set; }
    public int EmployeeId { get; set; }
    public DateTime CreatedDate { get; set; }
    public string Description { get; set; }
    public byte[] FileContent { get; set; }
    public string FileName { get; set; }
}

[HttpPut("resume")]
    public async Task<IActionResult> UploadResume([FromBody] EmployeeResume resume)
    {            
        if (resume == null)
        {
            return BadRequest();
        }


        return Ok();
    }
公共类EmployeeResume
{
public int ResumeId{get;set;}
public int EmployeeId{get;set;}
公共日期时间CreatedDate{get;set;}
公共字符串说明{get;set;}
公共字节[]文件内容{get;set;}
公共字符串文件名{get;set;}
}
[HttpPut(“恢复”)]
公共异步任务上载恢复([FromBody]EmployeeResume)
{            
if(resume==null)
{
返回请求();
}
返回Ok();
}
客户端:

// Model
export interface EmployeeResume {
    createdDate?: string;
    description?: string;
    employeeId: string;
    fileContent: any;
    fileName: string;    
    resumeId?: string;
}

// CHILD component
// -----------------------------------------------------------

// Kendo FileSelect in template
<kendo-fileselect
    formControlName="uploadFile"
    [restrictions]="uploadRestrictions"
    [multiple]="false"
    (select)="selectEventHandler($event)">
</kendo-fileselect>

// Sets a component property to the selected file
selectEventHandler(e: SelectEvent): void {
    this.uploadfile = e.files[0];
}

// When upload button is clicked, create the
// resume object and emit an event to parent
upload(): void {

    if (this.uploadfile.validationErrors) return;

    const thisComponent = this;
    const reader = new FileReader();

    reader.onload = function (ev) {
      const request = {
        description: thisComponent.f.description.value,
        employeeId: thisComponent.employeeId,
        fileContent: ev.target.result,
        fileName: thisComponent.uploadfile.name
      } as EmployeeResume;

      thisComponent.onUpload.emit(request);
    }

    reader.readAsDataURL(this.uploadfile.rawFile);    
}

// PARENT component
// -----------------------------------------------------------

// Template
<app-employee-resume
    [employeeId]="(employeeId$ | async)"
    (onUpload)="uploadResume($event)">
</app-employee-resume>

// Handler
uploadResume(resume: EmployeeResume) {    
    this.svc.upsertResume(resume)
}

// 'svc'
upsertResume(resume: EmployeeResume) {
    return this.http.put(`${this.apiUrl}/employee/resume`, resume);
}
//模型
导出接口EmployeeResume{
createdDate?:字符串;
description?:字符串;
employeeId:字符串;
文件内容:任何;
文件名:字符串;
resumeId?:字符串;
}
//子组件
// -----------------------------------------------------------
//剑道文件在模板中选择
//将零部件特性设置为选定文件
selectEventHandler(e:SelectEvent):无效{
this.uploadfile=e.files[0];
}
//单击“上载”按钮时,创建
//恢复对象并向父对象发出事件
上载():无效{
如果(this.uploadfile.validationErrors)返回;
const thisComponent=this;
const reader=new FileReader();
reader.onload=功能(ev){
常量请求={
描述:thisComponent.f.description.value,
employeeId:thisComponent.employeeId,
fileContent:ev.target.result,
文件名:thisComponent.uploadfile.name
}作为雇员消费;
thisComponent.onUpload.emit(请求);
}
reader.readAsDataURL(this.uploadfile.rawFile);
}
//父组件
// -----------------------------------------------------------
//模板
//处理者
上传简历(简历:EmployeeResume){
此.svc.upsertResume(恢复)
}
//“svc”
上级简历(简历:EmployeeResume){
返回this.http.put(`${this.apirl}/employee/resume`,resume);
}

您可以使用ts FormData和自定义FileData对象,以及您要存储到DB中的任何额外属性:

  onFileSelected(e: SelectEvent): void {
    this.uploadfile = e.files[0].rawFile;
  }

upload(): void {

const formData = new FormData();
const fileForSave = new FileData();

fileForSave.fileCategoryId = FileCategory.EmployeeResume;
fileForSave.description = this.f['description'].value;
fileForSave.employeeId = this.employeeId;

if (this.uploadfile) formData.append('file', this.uploadfile);
formData.append('fileForSave', JSON.stringify(fileForSave));

this.onUpload.emit(formData);
this.resetForm();
  }

  addFile(form: FormData): Observable<FileData> {
    return this.http.post<FileData>(`${this.apiUrl}/file/`, form);
  }

可能您需要将JSON.stringify()对象转换为JSON.stringify(),请参阅以下链接:
    [HttpPost]
    public async Task<IActionResult> AddFile(
        IFormFile file,
        [ModelBinder(BinderType = typeof(JsonModelBinder))] Contracts.Entities.File fileForSave)
    {
        // Check any file validations if you want

        /* Save the IFormFile file to disk */

        /* Save entity fileForSave File object to the DB */

        return Ok(newFile);
    }
public class JsonModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        // Check the value sent in
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueProviderResult != ValueProviderResult.None)
        {
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            // Attempt to convert the input value
            var valueAsString = valueProviderResult.FirstValue;
            var result = Newtonsoft.Json.JsonConvert.DeserializeObject(valueAsString, bindingContext.ModelType);
            if (result != null)
            {
                bindingContext.Result = ModelBindingResult.Success(result);
                return Task.CompletedTask;
            }
        }

        return Task.CompletedTask;
    }
}