如何使用 ServiceStack 和 Angular 下载动态生成的 XML 文件?

How to download a dynamically generated XML file with ServiceStack and Angular?

以下代码在理论上可以工作,但缺少错误处理。我遇到的问题是,当使用服务堆栈创建的 url 打开新的 window 时,它开始下载 XML 文件。但是现在当服务器端发生错误时,您在这个只有堆栈跟踪的新页面上。

使用服务堆栈和 Angular 下载动态二进制文件(未存储在磁盘上)的正确方法是什么?

Angular 与 ServiceStack:

downloadExportXML(){
  const request = new GetRatingsExportRequest(this.request);
  const url = this.jsonServiceClient.createUrlFromDto("GET", request)
  window.open(url);
}

WebAPI (C#) 收集 XML 文件。

  public HttpResult Get(GetRatingsExportRequest request)
  {
      MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlContent));
      var result = new HttpResult(ms.ToArray());
      var disposition = $"attachment;filename=myfilename;";
      result.Headers.Add(HttpHeaders.ContentDisposition, disposition);
      return result;
  }

如果您 return 使用 Content-Disposition: attachment HTTP Header 的内容,浏览器会将其视为单独的文件下载。

如果您不希望 return 它作为正常 XML 响应。但是你 returning 它的方式是相当低效的,即调用 ToArray() 违背了使用 Stream 的目的,因为你已经强制将 Stream 的全部内容加载到内存中,而你应该只是return 流,以便它作为流异步写入 HTTP 响应,例如:

return new HttpResult(ms, MimeTypes.Xml);

但是,如果您已经将 XML 作为字符串获得,则您也不需要 MemoryStream 包装器的开销,只需 return XML 字符串 as-is,例如:

return new HttpResult(xmlContent, MimeTypes.Xml);

我无法让它工作。所以我创建了这个解决方法:使用 ServiceStack 方法 jsonServiceClient.createUrlFromDto() 生成 URL 以下载 XML,而不是通过 Angular HTTPClient 下载文件。

downloadExportXML(){
  const request = new GetRatingsExportRequest(this.request);
  const url = this.jsonServiceClient.createUrlFromDto("GET", request)

  this.httpClient.get(url, {observe: 'response', responseType: 'arraybuffer'})
    .subscribe((response) => {
      var contentDisposition = response.headers.get('content-disposition');
      this.downloadFile(response.body)
    },
    error => this.handleError()
  );
}

private downloadFile(blobData: ArrayBuffer)
{
    let file = new Blob([blobData], { type: 'application/binary' });
    let fileURL = URL.createObjectURL(file);
    let fileLink = document.createElement('a');
    fileLink.href = fileURL;
    fileLink.download = "MYFILENAME.pdf";
    fileLink.click();
}