【问题标题】:Angular / Web API: Sending FormFile information from Client to APIAngular / Web API:将 FormFile 信息从客户端发送到 API
【发布时间】:2020-04-18 00:12:08
【问题描述】:

我正在努力完成在我的 Angular 应用程序中创建一个具有 0-n 个子对象(文件“附件”)的对象(“票证”)并将信息发送到我的 dotnet 核心 Web Api 的任务。但这更像是一个合乎逻辑的问题。

当用户创建工单时,他应该能够向该工单添加附件。

关于如何上传文件的文章很多,但我想要的是用户在创建票证时上传附件。我不希望这样,因为如果用户取消票证创建,我的存储(Azure)中将有未使用的附件,并且如果没有对 TicketId 的引用(这次不存在),我将无法创建附件对象) 在带有实体框架的服务器端。

所以我喜欢先收集所有信息,如果用户说“创建工单”,所有信息都会发送到 API,

  1. Ticket 对象将被创建
  2. 文件将根据文件信息上传(到 Azure)
  3. 附件对象已创建
  4. 附件对象被添加到工单中,并且
  5. 所有内容都保存到数据库中

Angular(客户端)

用于收集工单数据和选择附件文件的表单。界面是这样的:

export interface ITicketCreate {
    subject: string;
    content: string;
    category: number;
    userId: string;
    userNickname: string;
    email: string;
    attachments: File[];
}

发送到 Api 的最终 Dto 对象如下所示:

具有 createTicket 功能的服务

export class SupportService {
  supportUrl = environment.SupportApiUrl;

constructor(private http: HttpClient) { }

  createTicket(model: ITicketCreate) {
    return this.http.post(this.supportUrl + 'tickets', model);
  }
...
}

以及 CreateTicketComponent 中的调用

ticket = {} as ITicketCreate;
...
ngOnInit() {
    this.ticket.attachments = [];
}

createTicket() {
    console.log(this.ticket);

    this.ticket.userId = this.authService.currentUser.id;
    this.ticket.userNickname = this.authService.currentUser.nickName;
    this.ticket.email = this.authService.currentUser.userName;

    this.supportService.createTicket(this.ticket).subscribe(next => {
      this.alertify.success('Ticket created');
      this.router.navigate(['/support/tickets']);
    }, error => {
      this.alertify.error(error);
      console.log(error);
    });
  }

Web API (.Net Core 2.2)

在服务器端,我有以下 Dto 来接收数据:

public class CreateTicketDto
{
    public string Subject { get; set; }
    public string Content { get; set; }
    public string UserId { get; set; }
    public string Email { get; set; }
    public string UserNickname { get; set; }
    public int Category { get; set; }

    public List<IFormFile> Attachments { get; set; } = new List<IFormFile>();
}

还有控制器动作

[HttpPost]
public async Task<IActionResult> CreateTicket(CreateTicketDto createTicket)

发送请求后我从 API 得到的错误是:

由于我没有输入控制器操作本身来进行调试,所以我的问题是:

  1. 这甚至可能是我喜欢的工作方式吗?
  2. 如果是,我错过了什么?

最好的问候, 凯

【问题讨论】:

    标签: angular asp.net-web-api .net-core asp.net-core-webapi


    【解决方案1】:

    实际的错误消息告诉您无法实例化接口/抽象类。这是正常的,因为你不能实例化一个接口或抽象类,你需要一个非抽象类来实例化它。因此,您需要查看此行

    public List<IFormFile> Attachments { get; set; } = new List<IFormFile>();
    

    并查看您是否设法消除障碍,可能通过使用 IFormFile 接口的完整实现类,因此当尝试添加附件时,您不会出现此错误。

    关于您的实际问题,您有多种选择:

    禁止在插入时上传附件

    这是一个简单的想法。在添加模式下,您只是不显示任何附件并且不允许上传文件,但在编辑时您允许它。您可能会显示文件上传部分的禁用版本,并确保在服务器端不存储任何尝试上传的内容。

    有两种单独的表单上传和文件上传

    在这种情况下,您会在所有情况下显示所有内容,甚至允许准备上传文件,但仅在实际创建票证时才允许上传附件

    为票证使用原型类

    您可以为票证实现一个原型类,因此,如果票证尚未创建,但已发送附件,则将使用创建它的用户的外键创建 ProtoTicket,以便您跟踪附件,并允许用户在实际创建工单之前上传附件。下次用户创建票证时,他/她对原始票证的所有附件都将与该新票证相关联,并且原始票证将被删除。您还可以定期进行清理原始票证的工作。我认为这是最好的解决方案,因为它提供了最好的用户体验并保护您的服务器免受垃圾文件的影响。

    【讨论】:

    • 谢谢,我现在实现了第二种方法。新年快乐!
    猜你喜欢
    • 2015-04-06
    • 2022-06-24
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多