From 7d33bf3dbc8ee617b21eaa3bd9d45b0c272e7f89 Mon Sep 17 00:00:00 2001 From: muhammedaltug Date: Tue, 11 Oct 2022 14:07:11 +0300 Subject: [PATCH 1/8] update theme style doc --- docs/en/UI/Angular/Theme-Configurations.md | 220 ++++++++++++++++++++- 1 file changed, 219 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Theme-Configurations.md b/docs/en/UI/Angular/Theme-Configurations.md index 85d22040df..bbd2b89c3c 100644 --- a/docs/en/UI/Angular/Theme-Configurations.md +++ b/docs/en/UI/Angular/Theme-Configurations.md @@ -1,3 +1,221 @@ # Angular UI: Theme Configurations -> This document is in draft version. \ No newline at end of file +As of ABP version 6.0, theme packages do not import styles as css modules. In order for theme packages to load styles, the following style configuration must be added to the angular.json file. + +## Lepton X Lite +```json +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css", + "inject": false, + "bundleName": "bootstrap-dim" +}, +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.css", + "inject": false, + "bundleName": "ng-bundle" +}, +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.css", + "inject": false, + "bundleName": "layout-bundle" +}, +{ + "input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.css", + "inject": false, + "bundleName": "abp-bundle" +}, +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.rtl.css", + "inject": false, + "bundleName": "bootstrap-dim.rtl" +}, +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.rtl.css", + "inject": false, + "bundleName": "ng-bundle.rtl" +}, +{ + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.rtl.css", + "inject": false, + "bundleName": "layout-bundle.rtl" +}, +{ + "input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.rtl.css", + "inject": false, + "bundleName": "abp-bundle.rtl" +}, +``` + +## Theme Basic +```json +{ + "input": "node_modules/bootstrap/dist/css/bootstrap.rtl.min.css", + "inject": false, + "bundleName": "bootstrap-rtl.min" +}, +{ + "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", + "inject": true, + "bundleName": "bootstrap-ltr.min" +}, +``` + +## Lepton X +```json +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/dark.css", + "inject": false, + "bundleName": "dark" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/light.css", + "inject": false, + "bundleName": "light" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/dim.css", + "inject": false, + "bundleName": "dim" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-dim.css", + "inject": false, + "bundleName": "bootstrap-dim" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-dark.css", + "inject": false, + "bundleName": "bootstrap-dark" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-light.css", + "inject": false, + "bundleName": "bootstrap-light" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/ng-bundle.css", + "inject": false, + "bundleName": "ng-bundle" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/side-menu/layout-bundle.css", + "inject": false, + "bundleName": "layout-bundle" +}, +{ + "input": "node_modules/@volosoft/abp.ng.theme.lepton-x/assets/css/abp-bundle.css", + "inject": false, + "bundleName": "abp-bundle" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/dark.rtl.css", + "inject": false, + "bundleName": "dark.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/light.rtl.css", + "inject": false, + "bundleName": "light.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/dim.rtl.css", + "inject": false, + "bundleName": "dim.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-dim.rtl.css", + "inject": false, + "bundleName": "bootstrap-dim.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-dark.rtl.css", + "inject": false, + "bundleName": "bootstrap-dark.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/bootstrap-light.rtl.css", + "inject": false, + "bundleName": "bootstrap-light.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/ng-bundle.rtl.css", + "inject": false, + "bundleName": "ng-bundle.rtl" +}, +{ + "input": "node_modules/@volosoft/ngx-lepton-x/assets/css/side-menu/layout-bundle.rtl.css", + "inject": false, + "bundleName": "layout-bundle.rtl" +}, +{ + "input": "node_modules/@volosoft/abp.ng.theme.lepton-x/assets/css/abp-bundle.rtl.css", + "inject": false, + "bundleName": "abp-bundle.rtl" +} +``` + +## Theme Lepton +```json +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton1.min.css", + "inject": false, + "bundleName": "lepton1" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton2.min.css", + "inject": false, + "bundleName": "lepton2" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton3.min.css", + "inject": false, + "bundleName": "lepton3" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton4.min.css", + "inject": false, + "bundleName": "lepton4" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton5.min.css", + "inject": false, + "bundleName": "lepton5" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton6.min.css", + "inject": false, + "bundleName": "lepton6" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton1.rtl.min.css", + "inject": false, + "bundleName": "lepton1.rtl" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton2.rtl.min.css", + "inject": false, + "bundleName": "lepton2.rtl" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton3.rtl.min.css", + "inject": false, + "bundleName": "lepton3.rtl" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton4.rtl.min.css", + "inject": false, + "bundleName": "lepton4.rtl" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton5.rtl.min.css", + "inject": false, + "bundleName": "lepton5.rtl" +}, +{ + "input": "node_modules/@volo/abp.ng.theme.lepton/dist/global/styles/lepton6.rtl.min.css", + "inject": false, + "bundleName": "lepton6.rtl" +}, +``` + + From 440ba870d6f81e67ca19734b0ff83044d9ae860a Mon Sep 17 00:00:00 2001 From: muhammedaltug Date: Tue, 11 Oct 2022 14:41:44 +0300 Subject: [PATCH 2/8] update doc --- docs/en/UI/Angular/Theme-Configurations.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/en/UI/Angular/Theme-Configurations.md b/docs/en/UI/Angular/Theme-Configurations.md index bbd2b89c3c..45301db9d5 100644 --- a/docs/en/UI/Angular/Theme-Configurations.md +++ b/docs/en/UI/Angular/Theme-Configurations.md @@ -1,7 +1,6 @@ # Angular UI: Theme Configurations -As of ABP version 6.0, theme packages do not import styles as css modules. In order for theme packages to load styles, the following style configuration must be added to the angular.json file. - +Theme packages no longer import styles as CSS modules as of ABP version 6.0. The following style setting needs to be included to the angular.json file in order for theme packages to load styles. ## Lepton X Lite ```json { From dce0cf7a6f2db9aa738fa2b15e1d6c2a627ccdc9 Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:17:51 +0300 Subject: [PATCH 3/8] tiny fix --- docs/en/UI/Angular/Theme-Configurations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Theme-Configurations.md b/docs/en/UI/Angular/Theme-Configurations.md index 45301db9d5..1ec4f56c5e 100644 --- a/docs/en/UI/Angular/Theme-Configurations.md +++ b/docs/en/UI/Angular/Theme-Configurations.md @@ -1,6 +1,6 @@ # Angular UI: Theme Configurations -Theme packages no longer import styles as CSS modules as of ABP version 6.0. The following style setting needs to be included to the angular.json file in order for theme packages to load styles. +Theme packages no longer import styles as CSS modules as of ABP version 6.0. The following style settings need to be included to the angular.json file in order for theme packages to load styles. ## Lepton X Lite ```json { From a8035679b45b2702fdb444ddd87e844301c529ad Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 18 Oct 2022 18:46:57 +0800 Subject: [PATCH 4/8] Fix download file Chinese name garbled problem --- .../Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs index 8c0ab4f538..4c5e1523ea 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; @@ -91,8 +92,9 @@ public class ClientProxyBase : ITransientDependency * it before we finish doing our work with the stream */ return (T)(object)new RemoteStreamContent( await responseContent.ReadAsStreamAsync(), + WebUtility.UrlDecode( responseContent.Headers?.ContentDisposition?.FileNameStar ?? - RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(), + RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString()), responseContent.Headers?.ContentType?.ToString(), responseContent.Headers?.ContentLength); } From 241b57b36fcb16e07491260956855723a6702121 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 19 Oct 2022 10:33:36 +0800 Subject: [PATCH 5/8] Improve --- .../ContentFormatters/RemoteStreamContentOutputFormatter.cs | 4 ++-- .../Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs index 5c5e7ed6c0..5f2ff67c6e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs @@ -27,10 +27,10 @@ public class RemoteStreamContentOutputFormatter : OutputFormatter context.HttpContext.Response.ContentType = remoteStream.ContentType; context.HttpContext.Response.ContentLength = remoteStream.ContentLength; - if (!remoteStream.FileName.IsNullOrWhiteSpace()) + if (!remoteStream.FileName.IsNullOrWhiteSpace() && !context.HttpContext.Response.Headers.ContainsKey(HeaderNames.ContentDisposition)) { var contentDisposition = new ContentDispositionHeaderValue("attachment"); - contentDisposition.SetHttpFileName(remoteStream.FileName); + contentDisposition.SetMimeFileName(remoteStream.FileName); context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString(); } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs index 4c5e1523ea..8c0ab4f538 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; @@ -92,9 +91,8 @@ public class ClientProxyBase : ITransientDependency * it before we finish doing our work with the stream */ return (T)(object)new RemoteStreamContent( await responseContent.ReadAsStreamAsync(), - WebUtility.UrlDecode( responseContent.Headers?.ContentDisposition?.FileNameStar ?? - RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString()), + RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(), responseContent.Headers?.ContentType?.ToString(), responseContent.Headers?.ContentLength); } From 88b64b4160dcf4e4ec953b18115bffc58343c71b Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 19 Oct 2022 10:40:42 +0800 Subject: [PATCH 6/8] Improve --- .../Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs index 5f2ff67c6e..e41616617d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs @@ -30,7 +30,7 @@ public class RemoteStreamContentOutputFormatter : OutputFormatter if (!remoteStream.FileName.IsNullOrWhiteSpace() && !context.HttpContext.Response.Headers.ContainsKey(HeaderNames.ContentDisposition)) { var contentDisposition = new ContentDispositionHeaderValue("attachment"); - contentDisposition.SetMimeFileName(remoteStream.FileName); + contentDisposition.SetHttpFileName(remoteStream.FileName); context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString(); } From f48ae4998127617f427ea677476a50320158ca8c Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 19 Oct 2022 11:07:19 +0800 Subject: [PATCH 7/8] Add unit tests --- .../RemoteStreamContentTestController.cs | 11 +++++++++++ .../RemoteStreamContentTestController_Tests.cs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs index 42c84a8037..f8568323fa 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs @@ -19,6 +19,17 @@ public class RemoteStreamContentTestController : AbpController memoryStream.Position = 0; return new RemoteStreamContent(memoryStream, "download.rtf", "application/rtf"); } + + [HttpGet] + [Route("Download-With-Custom-Content-Disposition")] + public async Task Download_With_Custom_Content_Disposition_Async() + { + var memoryStream = new MemoryStream(); + await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync")); + memoryStream.Position = 0; + Response.Headers.Add("Content-Disposition", "attachment; filename=myDownload.rtf"); + return new RemoteStreamContent(memoryStream, "download.rtf", "application/rtf"); + } [HttpPost] [Route("Upload")] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs index 1a60ab9d6b..af3b155f55 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs @@ -19,6 +19,16 @@ public class RemoteStreamContentTestController_Tests : AspNetCoreMvcTestBase result.Content.Headers.ContentLength.ShouldBe("DownloadAsync".Length); (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); } + + [Fact] + public async Task Download_With_Custom_Content_Disposition_Async() + { + var result = await GetResponseAsync("/api/remote-stream-content-test/download-with-custom-content-disposition"); + result.Content.Headers.ContentType?.ToString().ShouldBe("application/rtf"); + result.Content.Headers.ContentDisposition?.FileName.ShouldBe("myDownload.rtf"); + result.Content.Headers.ContentLength.ShouldBe("DownloadAsync".Length); + (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); + } [Fact] public async Task UploadAsync() From 31e5a079d79689266bc640f3fb7d961a024e6e05 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 19 Oct 2022 11:12:53 +0800 Subject: [PATCH 8/8] Add unit tests --- .../RemoteStreamContentTestController.cs | 10 ++++++++++ .../RemoteStreamContentTestController_Tests.cs | 13 ++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs index f8568323fa..5efebb4603 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs @@ -30,6 +30,16 @@ public class RemoteStreamContentTestController : AbpController Response.Headers.Add("Content-Disposition", "attachment; filename=myDownload.rtf"); return new RemoteStreamContent(memoryStream, "download.rtf", "application/rtf"); } + + [HttpGet] + [Route("Download_With_Chinese_File_Name")] + public async Task Download_With_Chinese_File_Name_Async() + { + var memoryStream = new MemoryStream(); + await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync")); + memoryStream.Position = 0; + return new RemoteStreamContent(memoryStream, "下载文件.rtf", "application/rtf"); + } [HttpPost] [Route("Upload")] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs index af3b155f55..321c0099f1 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; +using System.Web; using Shouldly; using Xunit; @@ -20,7 +21,7 @@ public class RemoteStreamContentTestController_Tests : AspNetCoreMvcTestBase (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); } - [Fact] + [Fact] public async Task Download_With_Custom_Content_Disposition_Async() { var result = await GetResponseAsync("/api/remote-stream-content-test/download-with-custom-content-disposition"); @@ -29,6 +30,16 @@ public class RemoteStreamContentTestController_Tests : AspNetCoreMvcTestBase result.Content.Headers.ContentLength.ShouldBe("DownloadAsync".Length); (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); } + + [Fact] + public async Task Download_With_Chinese_File_Name_Async() + { + var result = await GetResponseAsync("/api/remote-stream-content-test/download_with_chinese_file_name"); + result.Content.Headers.ContentType?.ToString().ShouldBe("application/rtf"); + result.Content.Headers.ContentDisposition?.FileNameStar.ShouldBe("下载文件.rtf"); + result.Content.Headers.ContentLength.ShouldBe("DownloadAsync".Length); + (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); + } [Fact] public async Task UploadAsync()