Skip to content

Commit

Permalink
添加断点续传文件结果和执行器支持
Browse files Browse the repository at this point in the history
引入了多个文件以支持断点续传功能:
- `ActionContextExtension.cs`:定义了 `SetContentDispositionHeaderInline` 扩展方法。
- `ControllerExtensions.cs`:定义了多个 `ResumeFile` 扩展方法。
- `IResumeFileResult.cs`:定义了 `IResumeFileResult` 接口。
- `ResumeFileContentResult.cs`:实现了支持断点续传的文件内容结果。
- `ResumeFileStreamResult.cs`:实现了支持断点续传的文件流结果。
- `ResumePhysicalFileResult.cs`:实现了支持断点续传的本地物理文件结果。
- `ResumeVirtualFileResult.cs`:实现了支持断点续传的虚拟路径文件结果。
- `ResumeFileContentResultExecutor.cs`:实现了 `ResumeFileContentResult` 的执行器。
- `ResumeFileStreamResultExecutor.cs`:实现了 `ResumeFileStreamResult` 的执行器。
- `ResumePhysicalFileResultExecutor.cs`:实现了 `ResumePhysicalFileResult` 的执行器。
- `ResumeVirtualFileResultExecutor.cs`:实现了 `ResumeVirtualFileResult` 的执行器。
  • Loading branch information
猿人易 committed Dec 7, 2024
1 parent 0b724e1 commit 07f955e
Show file tree
Hide file tree
Showing 11 changed files with 521 additions and 0 deletions.
33 changes: 33 additions & 0 deletions Pek.AspNetCore/Extensions/ActionContextExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;

using Pek.ResumeFileResult;

namespace Pek;

/// <summary>
/// ResumeFileHelper
/// </summary>
public static class ActionContextExtension
{
/// <summary>
/// 设置响应头ContentDispositionHeader
/// </summary>
/// <param name="context"></param>
/// <param name="result"></param>
public static void SetContentDispositionHeaderInline(this ActionContext context, IResumeFileResult result)
{
context.HttpContext.Response.Headers[HeaderNames.AccessControlExposeHeaders] = HeaderNames.ContentDisposition;
if (string.IsNullOrEmpty(result.FileDownloadName))
{
var contentDisposition = new ContentDispositionHeaderValue("inline");

if (!string.IsNullOrWhiteSpace(result.FileInlineName))
{
contentDisposition.SetHttpFileName(result.FileInlineName);
}

context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
}
}
}
157 changes: 157 additions & 0 deletions Pek.AspNetCore/Extensions/ControllerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using Microsoft.AspNetCore.Mvc;

using Pek.Mime;
using Pek.ResumeFileResult;

namespace Pek;

/// <summary>
/// Controller扩展方法
/// </summary>
public static class ControllerExtensions
{
private static readonly IMimeMapper _mimeMapper = new MimeMapper();
/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileContents">文件二进制流</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeFileContentResult ResumeFile(this ControllerBase controller, Byte[] fileContents, String contentType, String fileDownloadName) => ResumeFile(controller, fileContents, contentType, fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileContents">文件二进制流</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeFileContentResult ResumeFile(this ControllerBase controller, Byte[] fileContents, String fileDownloadName) => ResumeFile(controller, fileContents, _mimeMapper.GetMimeFromPath(fileDownloadName), fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileContents">文件二进制流</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <param name="etag">ETag</param>
/// <returns></returns>
public static ResumeFileContentResult ResumeFile(this ControllerBase controller, Byte[] fileContents, String? contentType, String fileDownloadName, String? etag)
{
return new ResumeFileContentResult(fileContents, contentType, etag)
{
FileDownloadName = fileDownloadName
};
}

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileStream">文件二进制流</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeFileStreamResult ResumeFile(this ControllerBase controller, FileStream fileStream, String contentType, String fileDownloadName) => ResumeFile(controller, fileStream, contentType, fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileStream">文件二进制流</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeFileStreamResult ResumeFile(this ControllerBase controller, FileStream fileStream, String fileDownloadName) => ResumeFile(controller, fileStream, _mimeMapper.GetMimeFromPath(fileDownloadName), fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="fileStream">文件二进制流</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <param name="etag">ETag</param>
/// <returns></returns>
public static ResumeFileStreamResult ResumeFile(this ControllerBase controller, FileStream fileStream, String? contentType, String fileDownloadName, String? etag)
{
return new ResumeFileStreamResult(fileStream, contentType, etag)
{
FileDownloadName = fileDownloadName
};
}

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="virtualPath">服务端本地文件的虚拟路径</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeVirtualFileResult ResumeFile(this ControllerBase controller, String virtualPath, String contentType, String fileDownloadName) => ResumeFile(controller, virtualPath, contentType, fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="virtualPath">服务端本地文件的虚拟路径</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumeVirtualFileResult ResumeFile(this ControllerBase controller, String virtualPath, String fileDownloadName) => ResumeFile(controller, virtualPath, _mimeMapper.GetMimeFromPath(virtualPath), fileDownloadName, null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="virtualPath">服务端本地文件的虚拟路径</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <param name="etag">ETag</param>
/// <returns></returns>
public static ResumeVirtualFileResult ResumeFile(this ControllerBase controller, String virtualPath, String? contentType, String fileDownloadName, String? etag)
{
return new ResumeVirtualFileResult(virtualPath, contentType, etag)
{
FileDownloadName = fileDownloadName
};
}

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="physicalPath">服务端本地文件的物理路径</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumePhysicalFileResult ResumePhysicalFile(this ControllerBase controller, String physicalPath, String contentType, String fileDownloadName) => ResumePhysicalFile(controller, physicalPath, contentType, fileDownloadName, etag: null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="physicalPath">服务端本地文件的物理路径</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <returns></returns>
public static ResumePhysicalFileResult ResumePhysicalFile(this ControllerBase controller, String physicalPath, String fileDownloadName) => ResumePhysicalFile(controller, physicalPath, _mimeMapper.GetMimeFromPath(physicalPath), fileDownloadName, etag: null);

/// <summary>
/// 可断点续传和多线程下载的FileResult
/// </summary>
/// <param name="controller"></param>
/// <param name="physicalPath">服务端本地文件的物理路径</param>
/// <param name="contentType">Content-Type</param>
/// <param name="fileDownloadName">下载的文件名</param>
/// <param name="etag">ETag</param>
/// <returns></returns>
public static ResumePhysicalFileResult ResumePhysicalFile(this ControllerBase controller, String physicalPath, String? contentType, String fileDownloadName, String? etag)
{
return new ResumePhysicalFileResult(physicalPath, contentType, etag)
{
FileDownloadName = fileDownloadName
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc;

namespace Pek.ResumeFileResult.Executor;

/// <summary>
/// 断点续传文件FileResult执行器
/// </summary>
internal class ResumeFileContentResultExecutor : FileContentResultExecutor, IActionResultExecutor<ResumeFileContentResult>
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="loggerFactory"></param>
public ResumeFileContentResultExecutor(ILoggerFactory loggerFactory) : base(loggerFactory)
{
}

/// <summary>
/// 执行Result
/// </summary>
/// <param name="context"></param>
/// <param name="result"></param>
/// <returns></returns>
public virtual Task ExecuteAsync(ActionContext context, ResumeFileContentResult result)
{
ArgumentNullException.ThrowIfNull(context);

ArgumentNullException.ThrowIfNull(result);

context.SetContentDispositionHeaderInline(result);
return base.ExecuteAsync(context, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace Pek.ResumeFileResult.Executor;

/// <summary>
/// 可断点续传的FileStreamResult执行器
/// </summary>
internal class ResumeFileStreamResultExecutor : FileStreamResultExecutor, IActionResultExecutor<ResumeFileStreamResult>
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="loggerFactory"></param>
public ResumeFileStreamResultExecutor(ILoggerFactory loggerFactory) : base(loggerFactory)
{
}

/// <summary>
/// 执行Result
/// </summary>
/// <param name="context"></param>
/// <param name="result"></param>
/// <returns></returns>
public virtual Task ExecuteAsync(ActionContext context, ResumeFileStreamResult result)
{
ArgumentNullException.ThrowIfNull(context);

ArgumentNullException.ThrowIfNull(result);

context.SetContentDispositionHeaderInline(result);

return base.ExecuteAsync(context, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace Pek.ResumeFileResult.Executor;

/// <summary>
/// 通过本地文件的可断点续传的FileResult执行器
/// </summary>
internal class ResumePhysicalFileResultExecutor : PhysicalFileResultExecutor, IActionResultExecutor<ResumePhysicalFileResult>
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="loggerFactory"></param>
public ResumePhysicalFileResultExecutor(ILoggerFactory loggerFactory) : base(loggerFactory)
{
}

/// <summary>
/// 执行Result
/// </summary>
/// <param name="context"></param>
/// <param name="result"></param>
/// <returns></returns>
public virtual Task ExecuteAsync(ActionContext context, ResumePhysicalFileResult result)
{
ArgumentNullException.ThrowIfNull(context);

ArgumentNullException.ThrowIfNull(result);

context.SetContentDispositionHeaderInline(result);
return base.ExecuteAsync(context, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace Pek.ResumeFileResult.Executor;

/// <summary>
/// 使用本地虚拟路径的可断点续传的FileResult
/// </summary>
internal class ResumeVirtualFileResultExecutor : VirtualFileResultExecutor, IActionResultExecutor<ResumeVirtualFileResult>
{
/// <summary>
/// 执行FileResult
/// </summary>
/// <param name="context"></param>
/// <param name="result"></param>
/// <returns></returns>
public virtual Task ExecuteAsync(ActionContext context, ResumeVirtualFileResult result)
{
ArgumentNullException.ThrowIfNull(context);

ArgumentNullException.ThrowIfNull(result);

context.SetContentDispositionHeaderInline(result);

return base.ExecuteAsync(context, result);
}

public ResumeVirtualFileResultExecutor(ILoggerFactory loggerFactory, IWebHostEnvironment hostingEnvironment) : base(loggerFactory, hostingEnvironment)
{
}
}
17 changes: 17 additions & 0 deletions Pek.AspNetCore/ResumeFileResult/IResumeFileResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Pek.ResumeFileResult;

/// <summary>
/// 可断点续传的FileResult
/// </summary>
public interface IResumeFileResult
{
/// <summary>
/// 文件下载名
/// </summary>
String FileDownloadName { get; set; }

/// <summary>
/// 给响应头的文件名
/// </summary>
String FileInlineName { get; set; }
}
Loading

0 comments on commit 07f955e

Please sign in to comment.