diff --git a/Util.sln b/Util.sln index cbb8af7e3..1df835ea9 100644 --- a/Util.sln +++ b/Util.sln @@ -267,11 +267,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Generators.Tests", "te EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "08-FileStorage", "08-FileStorage", "{E069CEB0-8092-4907-BC9D-C6B8BDE20AD2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.FileStorage", "src\Util.FileStorage\01-Util.FileStorage.csproj", "{6FC29D15-7581-4E29-9897-76DC5AEF2042}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.FileStorage", "src\Util.FileStorage\02-Util.FileStorage.csproj", "{6FC29D15-7581-4E29-9897-76DC5AEF2042}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.FileStorage.Minio", "src\Util.FileStorage.Minio\02-Util.FileStorage.Minio.csproj", "{3E81F8D0-06C7-4FD4-A5B0-E3D96E909646}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.FileStorage.Minio", "src\Util.FileStorage.Minio\03-Util.FileStorage.Minio.csproj", "{3E81F8D0-06C7-4FD4-A5B0-E3D96E909646}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.FileStorage.Aliyun", "src\Util.FileStorage.Aliyun\03-Util.FileStorage.Aliyun.csproj", "{C233FF83-E15D-4A17-8FF1-BBFF9E9DE210}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.FileStorage.Aliyun", "src\Util.FileStorage.Aliyun\04-Util.FileStorage.Aliyun.csproj", "{C233FF83-E15D-4A17-8FF1-BBFF9E9DE210}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "08-FileStorage", "08-FileStorage", "{16175228-03CA-414A-8786-E5BA844110C4}" EndProject @@ -339,10 +339,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "07-Util.Http", "src\Util.Ht EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.FileStorage.Tests.Integration", "test\Util.FileStorage.Tests.Integration\Util.FileStorage.Tests.Integration.csproj", "{A23BA1A3-8EC7-4937-B0AA-69CCEE40453C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.FileStorage.All", "src\Util.FileStorage.All\04-Util.FileStorage.All.csproj", "{4938D59D-CF50-4090-B936-36DB29EBE344}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "05-Util.FileStorage.All", "src\Util.FileStorage.All\05-Util.FileStorage.All.csproj", "{4938D59D-CF50-4090-B936-36DB29EBE344}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.FileStorage.Aliyun.Tests.Integration", "test\Util.FileStorage.Aliyun.Tests.Integration\Util.FileStorage.Aliyun.Tests.Integration.csproj", "{58C01936-5D8F-4077-8663-EE0E35776D65}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.FileStorage.Abstractions", "src\Util.FileStorage.Abstractions\01-Util.FileStorage.Abstractions.csproj", "{814E42E9-508E-487F-BCD3-0F07AE7D1492}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -857,6 +859,10 @@ Global {58C01936-5D8F-4077-8663-EE0E35776D65}.Debug|Any CPU.Build.0 = Debug|Any CPU {58C01936-5D8F-4077-8663-EE0E35776D65}.Release|Any CPU.ActiveCfg = Release|Any CPU {58C01936-5D8F-4077-8663-EE0E35776D65}.Release|Any CPU.Build.0 = Release|Any CPU + {814E42E9-508E-487F-BCD3-0F07AE7D1492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {814E42E9-508E-487F-BCD3-0F07AE7D1492}.Debug|Any CPU.Build.0 = Debug|Any CPU + {814E42E9-508E-487F-BCD3-0F07AE7D1492}.Release|Any CPU.ActiveCfg = Release|Any CPU + {814E42E9-508E-487F-BCD3-0F07AE7D1492}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1027,6 +1033,7 @@ Global {A23BA1A3-8EC7-4937-B0AA-69CCEE40453C} = {16175228-03CA-414A-8786-E5BA844110C4} {4938D59D-CF50-4090-B936-36DB29EBE344} = {E069CEB0-8092-4907-BC9D-C6B8BDE20AD2} {58C01936-5D8F-4077-8663-EE0E35776D65} = {16175228-03CA-414A-8786-E5BA844110C4} + {814E42E9-508E-487F-BCD3-0F07AE7D1492} = {E069CEB0-8092-4907-BC9D-C6B8BDE20AD2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94347832-A36D-4C42-9C4D-B848BD4F5DA9} diff --git a/build/version.props b/build/version.props index 92d67f8b7..d100b181f 100644 --- a/build/version.props +++ b/build/version.props @@ -2,7 +2,7 @@ 7 1 - 123 + 125 $(VersionMajor).$(VersionMinor).$(VersionPatch) diff --git a/src/Util.Aop.AspectCore/AopOptions.cs b/src/Util.Aop.AspectCore/AopOptions.cs new file mode 100644 index 000000000..6e56f1701 --- /dev/null +++ b/src/Util.Aop.AspectCore/AopOptions.cs @@ -0,0 +1,15 @@ +namespace Util.Aop; + +/// +/// Aop配置 +/// +public class AopOptions { + /// + /// 是否启用IAopProxy接口标记 + /// + public bool IsEnableIAopProxy { get; set; } + /// + /// 是否启用参数拦截器,默认值: true + /// + public bool IsEnableParameterAspect { get; set; } = true; +} \ No newline at end of file diff --git a/src/Util.Aop.AspectCore/AppBuilderExtensions.cs b/src/Util.Aop.AspectCore/AppBuilderExtensions.cs index dfc53b9c4..6c52982c2 100644 --- a/src/Util.Aop.AspectCore/AppBuilderExtensions.cs +++ b/src/Util.Aop.AspectCore/AppBuilderExtensions.cs @@ -39,10 +39,22 @@ public static IAppBuilder AddAop( this IAppBuilder builder, ActionAspectCore拦截器配置操作 /// 是否启用IAopProxy接口标记 private static IAppBuilder AddAop( this IAppBuilder builder, Action setupAction, bool isEnableIAopProxy ) { + return builder.AddAop( setupAction, t => t.IsEnableIAopProxy = isEnableIAopProxy ); + } + + /// + /// 启用AspectCore拦截器 + /// + /// 应用生成器 + /// AspectCore拦截器配置操作 + /// 配置操作 + private static IAppBuilder AddAop( this IAppBuilder builder, Action setupAction, Action action ) { builder.CheckNull( nameof( builder ) ); builder.Host.UseServiceProviderFactory( new DynamicProxyServiceProviderFactory() ); builder.Host.ConfigureServices( ( context, services ) => { - ConfigureDynamicProxy( services, setupAction, isEnableIAopProxy ); + var options = new AopOptions(); + action?.Invoke( options ); + ConfigureDynamicProxy( services, setupAction, options.IsEnableParameterAspect,options.IsEnableIAopProxy ); RegisterAspectScoped( services ); } ); return builder; @@ -51,11 +63,12 @@ private static IAppBuilder AddAop( this IAppBuilder builder, Action /// 配置拦截器 /// - private static void ConfigureDynamicProxy( IServiceCollection services, Action setupAction, bool isEnableIAopProxy ) { + private static void ConfigureDynamicProxy( IServiceCollection services, Action setupAction,bool isEnableParameterAspect, bool isEnableIAopProxy ) { services.ConfigureDynamicProxy( config => { if ( setupAction == null ) { config.NonAspectPredicates.Add( t => !IsProxy( t.DeclaringType, isEnableIAopProxy ) ); - config.EnableParameterAspect(); + if( isEnableParameterAspect ) + config.EnableParameterAspect(); return; } setupAction.Invoke( config ); @@ -69,9 +82,7 @@ private static bool IsProxy( Type type, bool isEnableIAopProxy ) { if ( type == null ) return false; if ( isEnableIAopProxy == false ) { - if ( type.SafeString().Contains( "Xunit.DependencyInjection.ITestOutputHelperAccessor" ) ) - return false; - return true; + return type.SafeString().Contains( "Xunit.DependencyInjection.ITestOutputHelperAccessor" ) == false; } var interfaces = type.GetInterfaces(); if ( interfaces == null || interfaces.Length == 0 ) diff --git a/src/Util.FileStorage.Abstractions/01-Util.FileStorage.Abstractions.csproj b/src/Util.FileStorage.Abstractions/01-Util.FileStorage.Abstractions.csproj new file mode 100644 index 000000000..e81d9142a --- /dev/null +++ b/src/Util.FileStorage.Abstractions/01-Util.FileStorage.Abstractions.csproj @@ -0,0 +1,33 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.FileStorage.Abstractions + Util.FileStorage + Util.FileStorage.Abstractions是Util应用框架文件存储操作接口定义类库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.FileStorage.Abstractions.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.FileStorage.Abstractions.xml + + + + + True + False + + + + + + + + + diff --git a/src/Util.FileStorage/DeleteFileArgs.cs b/src/Util.FileStorage.Abstractions/DeleteFileArgs.cs similarity index 100% rename from src/Util.FileStorage/DeleteFileArgs.cs rename to src/Util.FileStorage.Abstractions/DeleteFileArgs.cs diff --git a/src/Util.FileStorage/DirectUploadParam.cs b/src/Util.FileStorage.Abstractions/DirectUploadParam.cs similarity index 100% rename from src/Util.FileStorage/DirectUploadParam.cs rename to src/Util.FileStorage.Abstractions/DirectUploadParam.cs diff --git a/src/Util.FileStorage/FileExistsArgs.cs b/src/Util.FileStorage.Abstractions/FileExistsArgs.cs similarity index 100% rename from src/Util.FileStorage/FileExistsArgs.cs rename to src/Util.FileStorage.Abstractions/FileExistsArgs.cs diff --git a/src/Util.FileStorage/FileResult.cs b/src/Util.FileStorage.Abstractions/FileResult.cs similarity index 100% rename from src/Util.FileStorage/FileResult.cs rename to src/Util.FileStorage.Abstractions/FileResult.cs diff --git a/src/Util.FileStorage/FileSize.cs b/src/Util.FileStorage.Abstractions/FileSize.cs similarity index 72% rename from src/Util.FileStorage/FileSize.cs rename to src/Util.FileStorage.Abstractions/FileSize.cs index 4b343059d..ed5355565 100644 --- a/src/Util.FileStorage/FileSize.cs +++ b/src/Util.FileStorage.Abstractions/FileSize.cs @@ -18,6 +18,15 @@ public FileSize( long size, FileSizeUnit unit = FileSizeUnit.Byte ) { _size = GetSize( size, unit ); } + /// + /// 初始化文件大小 + /// + /// 文件大小 + /// 文件大小单位 + public FileSize( double size, FileSizeUnit unit = FileSizeUnit.Byte ) { + _size = Util.Helpers.Convert.ToLong( GetSize( size, unit ) ); + } + /// /// 获取文件大小 /// @@ -34,6 +43,22 @@ private static long GetSize( long size, FileSizeUnit unit ) { } } + /// + /// 获取文件大小 + /// + private static double GetSize( double size, FileSizeUnit unit ) { + switch( unit ) { + case FileSizeUnit.K: + return size * 1024; + case FileSizeUnit.M: + return size * 1024 * 1024; + case FileSizeUnit.G: + return size * 1024 * 1024 * 1024; + default: + return size; + } + } + /// /// 文件字节长度 /// diff --git a/src/Util.FileStorage/FileSizeUnit.cs b/src/Util.FileStorage.Abstractions/FileSizeUnit.cs similarity index 100% rename from src/Util.FileStorage/FileSizeUnit.cs rename to src/Util.FileStorage.Abstractions/FileSizeUnit.cs diff --git a/src/Util.FileStorage/FileStorageArgs.cs b/src/Util.FileStorage.Abstractions/FileStorageArgs.cs similarity index 100% rename from src/Util.FileStorage/FileStorageArgs.cs rename to src/Util.FileStorage.Abstractions/FileStorageArgs.cs diff --git a/src/Util.FileStorage/FileStorageInfo.cs b/src/Util.FileStorage.Abstractions/FileStorageInfo.cs similarity index 100% rename from src/Util.FileStorage/FileStorageInfo.cs rename to src/Util.FileStorage.Abstractions/FileStorageInfo.cs diff --git a/src/Util.FileStorage/GenerateDownloadUrlArgs.cs b/src/Util.FileStorage.Abstractions/GenerateDownloadUrlArgs.cs similarity index 100% rename from src/Util.FileStorage/GenerateDownloadUrlArgs.cs rename to src/Util.FileStorage.Abstractions/GenerateDownloadUrlArgs.cs diff --git a/src/Util.FileStorage/GenerateUploadUrlArgs.cs b/src/Util.FileStorage.Abstractions/GenerateUploadUrlArgs.cs similarity index 88% rename from src/Util.FileStorage/GenerateUploadUrlArgs.cs rename to src/Util.FileStorage.Abstractions/GenerateUploadUrlArgs.cs index d20a3c3fe..132eee52f 100644 --- a/src/Util.FileStorage/GenerateUploadUrlArgs.cs +++ b/src/Util.FileStorage.Abstractions/GenerateUploadUrlArgs.cs @@ -48,4 +48,9 @@ public void AddHeader( string key,string value ) { public IDictionary GetHeaders() { return _headers; } + + /// + /// 文件大小限制,单位:字节 + /// + public long SizeLimit { get; set; } } \ No newline at end of file diff --git a/src/Util.FileStorage/GetFileStreamArgs.cs b/src/Util.FileStorage.Abstractions/GetFileStreamArgs.cs similarity index 100% rename from src/Util.FileStorage/GetFileStreamArgs.cs rename to src/Util.FileStorage.Abstractions/GetFileStreamArgs.cs diff --git a/src/Util.FileStorage/IBucketNameProcessor.cs b/src/Util.FileStorage.Abstractions/IBucketNameProcessor.cs similarity index 100% rename from src/Util.FileStorage/IBucketNameProcessor.cs rename to src/Util.FileStorage.Abstractions/IBucketNameProcessor.cs diff --git a/src/Util.FileStorage/IBucketNameProcessorFactory.cs b/src/Util.FileStorage.Abstractions/IBucketNameProcessorFactory.cs similarity index 100% rename from src/Util.FileStorage/IBucketNameProcessorFactory.cs rename to src/Util.FileStorage.Abstractions/IBucketNameProcessorFactory.cs diff --git a/src/Util.FileStorage/IFileExtensionInspector.cs b/src/Util.FileStorage.Abstractions/IFileExtensionInspector.cs similarity index 100% rename from src/Util.FileStorage/IFileExtensionInspector.cs rename to src/Util.FileStorage.Abstractions/IFileExtensionInspector.cs diff --git a/src/Util.FileStorage/IFileNameFilter.cs b/src/Util.FileStorage.Abstractions/IFileNameFilter.cs similarity index 100% rename from src/Util.FileStorage/IFileNameFilter.cs rename to src/Util.FileStorage.Abstractions/IFileNameFilter.cs diff --git a/src/Util.FileStorage/IFileNameProcessor.cs b/src/Util.FileStorage.Abstractions/IFileNameProcessor.cs similarity index 100% rename from src/Util.FileStorage/IFileNameProcessor.cs rename to src/Util.FileStorage.Abstractions/IFileNameProcessor.cs diff --git a/src/Util.FileStorage/IFileNameProcessorFactory.cs b/src/Util.FileStorage.Abstractions/IFileNameProcessorFactory.cs similarity index 100% rename from src/Util.FileStorage/IFileNameProcessorFactory.cs rename to src/Util.FileStorage.Abstractions/IFileNameProcessorFactory.cs diff --git a/src/Util.FileStorage/IFileStore.cs b/src/Util.FileStorage.Abstractions/IFileStore.cs similarity index 100% rename from src/Util.FileStorage/IFileStore.cs rename to src/Util.FileStorage.Abstractions/IFileStore.cs diff --git a/src/Util.FileStorage/ILocalFileStore.cs b/src/Util.FileStorage.Abstractions/ILocalFileStore.cs similarity index 100% rename from src/Util.FileStorage/ILocalFileStore.cs rename to src/Util.FileStorage.Abstractions/ILocalFileStore.cs diff --git a/src/Util.FileStorage/ProcessedName.cs b/src/Util.FileStorage.Abstractions/ProcessedName.cs similarity index 100% rename from src/Util.FileStorage/ProcessedName.cs rename to src/Util.FileStorage.Abstractions/ProcessedName.cs diff --git a/src/Util.FileStorage/SaveFileArgs.cs b/src/Util.FileStorage.Abstractions/SaveFileArgs.cs similarity index 100% rename from src/Util.FileStorage/SaveFileArgs.cs rename to src/Util.FileStorage.Abstractions/SaveFileArgs.cs diff --git a/src/Util.FileStorage/SaveFileByUrlArgs.cs b/src/Util.FileStorage.Abstractions/SaveFileByUrlArgs.cs similarity index 100% rename from src/Util.FileStorage/SaveFileByUrlArgs.cs rename to src/Util.FileStorage.Abstractions/SaveFileByUrlArgs.cs diff --git a/src/Util.FileStorage.Abstractions/Usings.cs b/src/Util.FileStorage.Abstractions/Usings.cs new file mode 100644 index 000000000..a14c45150 --- /dev/null +++ b/src/Util.FileStorage.Abstractions/Usings.cs @@ -0,0 +1,11 @@ +global using System; +global using System.Threading.Tasks; +global using System.Collections.Generic; +global using System.Threading; +global using System.IO; +global using System.ComponentModel; +global using System.Linq; +global using Microsoft.Extensions.Options; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Util.Dependency; diff --git a/src/Util.FileStorage.Aliyun/03-Util.FileStorage.Aliyun.csproj b/src/Util.FileStorage.Aliyun/04-Util.FileStorage.Aliyun.csproj similarity index 92% rename from src/Util.FileStorage.Aliyun/03-Util.FileStorage.Aliyun.csproj rename to src/Util.FileStorage.Aliyun/04-Util.FileStorage.Aliyun.csproj index df0838c48..c940a47c6 100644 --- a/src/Util.FileStorage.Aliyun/03-Util.FileStorage.Aliyun.csproj +++ b/src/Util.FileStorage.Aliyun/04-Util.FileStorage.Aliyun.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Util.FileStorage.Aliyun/AliyunFileStore.cs b/src/Util.FileStorage.Aliyun/AliyunFileStore.cs index 970e5c1f8..7a7b680dd 100644 --- a/src/Util.FileStorage.Aliyun/AliyunFileStore.cs +++ b/src/Util.FileStorage.Aliyun/AliyunFileStore.cs @@ -442,16 +442,16 @@ protected async Task ProcessBucketName( FileStorageArgs args ) { args.CheckNull( nameof( args ) ); var processedFileName = ProcessFileName( args ); var processedBucketName = await ProcessBucketName( args ); - return await GenerateUploadUrlAsync( processedFileName, processedBucketName, cancellationToken ); + return await GenerateUploadUrlAsync( processedFileName, processedBucketName, args.SizeLimit ); } /// /// 生成直传Url /// - protected async Task GenerateUploadUrlAsync( ProcessedName fileName, ProcessedName bucketName, CancellationToken cancellationToken ) { + protected async Task GenerateUploadUrlAsync( ProcessedName fileName, ProcessedName bucketName, long sizeLimit ) { await InitConfig(); var url = CreateGenerateUploadHost( bucketName.Name ); - var data = await CreateGenerateUploadData( fileName, bucketName, cancellationToken ); + var data = await CreateGenerateUploadData( fileName, bucketName, sizeLimit ); return new DirectUploadParam( fileName.Name, url, data, fileName.OriginalName, bucketName.Name ); } @@ -472,8 +472,8 @@ protected string CreateGenerateUploadHost( string bucketName ) { /// /// 创建直传数据 /// - protected async Task CreateGenerateUploadData( ProcessedName fileName, ProcessedName bucketName, CancellationToken cancellationToken ) { - var policy = await GetPostPolicy( bucketName ); + protected async Task CreateGenerateUploadData( ProcessedName fileName, ProcessedName bucketName, long sizeLimit ) { + var policy = await GetPostPolicy( bucketName, sizeLimit ); var signature = ComputeSignature( _config.AccessKeySecret, policy ); return new DirectUploadData( fileName.Name, policy, _config.AccessKeyId, signature ); } @@ -481,11 +481,12 @@ protected async Task CreateGenerateUploadData( ProcessedName f /// /// 获取Post策略 /// - protected virtual async Task GetPostPolicy( ProcessedName bucketName ) { + protected virtual async Task GetPostPolicy( ProcessedName bucketName,long sizeLimit ) { var client = await GetClient(); var expiration = DateTime.Now.AddSeconds( _config.UploadUrlExpiration ); var policy = new PolicyConditions(); policy.AddConditionItem( "bucket", bucketName.Name ); + policy.AddConditionItem( "content-length-range", 1,sizeLimit ); var postPolicy = client.GeneratePostPolicy( expiration, policy ); return Util.Helpers.Convert.ToBase64( postPolicy ); } diff --git a/src/Util.FileStorage.All/04-Util.FileStorage.All.csproj b/src/Util.FileStorage.All/05-Util.FileStorage.All.csproj similarity index 87% rename from src/Util.FileStorage.All/04-Util.FileStorage.All.csproj rename to src/Util.FileStorage.All/05-Util.FileStorage.All.csproj index 5e8d68dc3..9467de684 100644 --- a/src/Util.FileStorage.All/04-Util.FileStorage.All.csproj +++ b/src/Util.FileStorage.All/05-Util.FileStorage.All.csproj @@ -27,8 +27,8 @@ - - + + diff --git a/src/Util.FileStorage.All/FileStoreFactory.cs b/src/Util.FileStorage.All/FileStoreFactory.cs index 3f97ad522..e00551e9b 100644 --- a/src/Util.FileStorage.All/FileStoreFactory.cs +++ b/src/Util.FileStorage.All/FileStoreFactory.cs @@ -13,10 +13,6 @@ public class FileStoreFactory : IFileStoreFactory { /// private readonly IBucketNameProcessorFactory _bucketNameProcessorFactory; /// - /// 文件扩展名检查器 - /// - private readonly IFileExtensionInspector _inspector; - /// /// Http操作 /// private readonly IHttpClient _httpClient; @@ -32,19 +28,17 @@ public class FileStoreFactory : IFileStoreFactory { /// 存储桶名称处理器工厂 /// Http客户端工厂 /// Http操作 - /// 文件扩展名检查器 public FileStoreFactory( IFileNameProcessorFactory fileNameProcessorFactory, IBucketNameProcessorFactory bucketNameProcessorFactory, - IHttpClientFactory httpClientFactory, IHttpClient httpClient, IFileExtensionInspector inspector ) { + IHttpClientFactory httpClientFactory, IHttpClient httpClient ) { _fileNameProcessorFactory = fileNameProcessorFactory ?? throw new ArgumentNullException( nameof( fileNameProcessorFactory ) ); _bucketNameProcessorFactory = bucketNameProcessorFactory ?? throw new ArgumentNullException( nameof( bucketNameProcessorFactory ) ); _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException( nameof( httpClientFactory ) ); _httpClient = httpClient ?? throw new ArgumentNullException( nameof( httpClient ) ); - _inspector = inspector ?? throw new ArgumentNullException( nameof( inspector ) ); } /// public IFileStore Create( LocalStoreOptions options ) { - return new LocalFileStore( new LocalStoreConfigProvider( options ), _fileNameProcessorFactory, _inspector, _httpClient ); + return new LocalFileStore( new LocalStoreConfigProvider( options ), _fileNameProcessorFactory, _httpClient ); } /// diff --git a/src/Util.FileStorage.Minio/02-Util.FileStorage.Minio.csproj b/src/Util.FileStorage.Minio/03-Util.FileStorage.Minio.csproj similarity index 92% rename from src/Util.FileStorage.Minio/02-Util.FileStorage.Minio.csproj rename to src/Util.FileStorage.Minio/03-Util.FileStorage.Minio.csproj index 82ab966fe..18c956652 100644 --- a/src/Util.FileStorage.Minio/02-Util.FileStorage.Minio.csproj +++ b/src/Util.FileStorage.Minio/03-Util.FileStorage.Minio.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Util.FileStorage/01-Util.FileStorage.csproj b/src/Util.FileStorage/02-Util.FileStorage.csproj similarity index 89% rename from src/Util.FileStorage/01-Util.FileStorage.csproj rename to src/Util.FileStorage/02-Util.FileStorage.csproj index 4081506c9..9f22f2682 100644 --- a/src/Util.FileStorage/01-Util.FileStorage.csproj +++ b/src/Util.FileStorage/02-Util.FileStorage.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Util.FileStorage/IFileStoreExtensions.cs b/src/Util.FileStorage/FileStoreExtensions.cs similarity index 96% rename from src/Util.FileStorage/IFileStoreExtensions.cs rename to src/Util.FileStorage/FileStoreExtensions.cs index 5ad00c7bd..80c7bdf08 100644 --- a/src/Util.FileStorage/IFileStoreExtensions.cs +++ b/src/Util.FileStorage/FileStoreExtensions.cs @@ -3,7 +3,7 @@ /// /// 文件存储服务操作扩展 /// -public static class IFileStoreExtensions { +public static class FileStoreExtensions { /// /// 保存文件 /// diff --git a/src/Util.FileStorage/FileValidation.cs b/src/Util.FileStorage/FileValidation.cs new file mode 100644 index 000000000..a66cc8ca6 --- /dev/null +++ b/src/Util.FileStorage/FileValidation.cs @@ -0,0 +1,23 @@ +namespace Util.FileStorage; + +/// +/// 文件验证操作 +/// +public static class FileValidation { + /// + /// 扩展名是否有效 + /// + /// 文件名,范例: a.jpg + /// 接受的扩展名列表,以逗号分隔,范例: .jpg,.png,.gif + public static bool IsValidExtension( string fileName, string accepts ) { + if( fileName.IsEmpty() ) + return false; + if( accepts.IsEmpty() ) + return true; + var extension = Path.GetExtension( fileName ); + var list = accepts.Split( ',' ).Where( t => t.IsEmpty() == false ).ToList(); + if ( list.Count == 0 ) + return true; + return list.Any( type => type.TrimStart( '.' ) == extension.TrimStart( '.' ) ); + } +} \ No newline at end of file diff --git a/src/Util.FileStorage/Local/LocalFileStore.cs b/src/Util.FileStorage/Local/LocalFileStore.cs index 82180cc11..894d099ef 100644 --- a/src/Util.FileStorage/Local/LocalFileStore.cs +++ b/src/Util.FileStorage/Local/LocalFileStore.cs @@ -16,10 +16,6 @@ public class LocalFileStore : IFileStore { /// private readonly IFileNameProcessorFactory _fileNameProcessorFactory; /// - /// 文件扩展名检查器 - /// - private readonly IFileExtensionInspector _inspector; - /// /// 本地文件存储配置 /// private LocalStoreOptions _config; @@ -37,13 +33,10 @@ public class LocalFileStore : IFileStore { /// /// 配置提供器 /// 文件名处理器工厂 - /// 文件扩展名检查器 /// Http操作 - public LocalFileStore( ILocalStoreConfigProvider configProvider, IFileNameProcessorFactory fileNameProcessorFactory, - IFileExtensionInspector inspector, IHttpClient httpClient ) { + public LocalFileStore( ILocalStoreConfigProvider configProvider, IFileNameProcessorFactory fileNameProcessorFactory, IHttpClient httpClient ) { _configProvider = configProvider ?? throw new ArgumentNullException( nameof( configProvider ) ); _fileNameProcessorFactory = fileNameProcessorFactory ?? throw new ArgumentNullException( nameof( fileNameProcessorFactory ) ); - _inspector = inspector ?? throw new ArgumentNullException( nameof( inspector ) ); _httpClient = httpClient ?? throw new ArgumentNullException( nameof( httpClient ) ); } @@ -177,7 +170,6 @@ protected virtual async Task GetPhysicalPath( ProcessedName fileName ) { /// public virtual async Task SaveFileAsync( Stream stream, ProcessedName fileName, CancellationToken cancellationToken = default ) { stream.CheckNull( nameof( stream ) ); - ValidateExtension( stream, fileName.OriginalName ); var config = await GetConfig(); var filePath = Path.Combine( config.RootPath, fileName.Name ); var physicalPath = Path.Combine( Util.Helpers.Web.Environment.WebRootPath, filePath ); @@ -185,21 +177,6 @@ protected virtual async Task GetPhysicalPath( ProcessedName fileName ) { return new FileResult( filePath, stream.Length, fileName.OriginalName ); } - /// - /// 验证扩展名 - /// - protected virtual void ValidateExtension( Stream stream, string fileName ) { - var extension = Path.GetExtension( fileName ); - if( extension.IsEmpty() ) - return; - var result = _inspector.GetExtension( stream ); - if( result.IsEmpty() ) - return; - extension = extension.TrimStart( '.' ).ToUpperInvariant(); - if( extension != result.ToUpperInvariant() ) - throw new InvalidOperationException( $"上传文件扩展名检查失败,文件名:{fileName},扩展名: {extension} != {result}" ); - } - #endregion #region SaveFileByUrlAsync diff --git a/src/Util.FileStorage/Usings.cs b/src/Util.FileStorage/Usings.cs index 8866e559d..d87a5e5d0 100644 --- a/src/Util.FileStorage/Usings.cs +++ b/src/Util.FileStorage/Usings.cs @@ -4,6 +4,7 @@ global using System.Threading; global using System.IO; global using System.ComponentModel; +global using System.Linq; global using Microsoft.Extensions.Options; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/test/Util.FileStorage.Aliyun.Tests.Integration/Util.FileStorage.Aliyun.Tests.Integration.csproj b/test/Util.FileStorage.Aliyun.Tests.Integration/Util.FileStorage.Aliyun.Tests.Integration.csproj index 320854b35..ee228c814 100644 --- a/test/Util.FileStorage.Aliyun.Tests.Integration/Util.FileStorage.Aliyun.Tests.Integration.csproj +++ b/test/Util.FileStorage.Aliyun.Tests.Integration/Util.FileStorage.Aliyun.Tests.Integration.csproj @@ -40,7 +40,7 @@ - + diff --git a/test/Util.FileStorage.Minio.Tests.Integration/Util.FileStorage.Minio.Tests.Integration.csproj b/test/Util.FileStorage.Minio.Tests.Integration/Util.FileStorage.Minio.Tests.Integration.csproj index 09f4591fb..651e52ef1 100644 --- a/test/Util.FileStorage.Minio.Tests.Integration/Util.FileStorage.Minio.Tests.Integration.csproj +++ b/test/Util.FileStorage.Minio.Tests.Integration/Util.FileStorage.Minio.Tests.Integration.csproj @@ -39,7 +39,7 @@ - + diff --git a/test/Util.FileStorage.Tests.Integration/Tests/FileValidationTest.cs b/test/Util.FileStorage.Tests.Integration/Tests/FileValidationTest.cs new file mode 100644 index 000000000..c3d774b9c --- /dev/null +++ b/test/Util.FileStorage.Tests.Integration/Tests/FileValidationTest.cs @@ -0,0 +1,28 @@ +namespace Util.FileStorage.Tests; + +/// +/// 文件验证操作测试 +/// +public class FileValidationTest { + /// + /// 测试扩展名是否有效 + /// + [Fact] + public void TestIsValidExtension() { + Assert.True( FileValidation.IsValidExtension( "a.jpg", "" ) ); + Assert.False( FileValidation.IsValidExtension( "", ".jpg" ) ); + Assert.True( FileValidation.IsValidExtension( "a.jpg", ".jpg" ) ); + Assert.True( FileValidation.IsValidExtension( "a.jpg", "jpg" ) ); + Assert.False( FileValidation.IsValidExtension( "a.png", ".jpg" ) ); + Assert.True( FileValidation.IsValidExtension( "a.jpg", ".jpg,.png" ) ); + Assert.True( FileValidation.IsValidExtension( "a.png", ".jpg,.png" ) ); + Assert.True( FileValidation.IsValidExtension( "a.jpg", "jpg,png" ) ); + Assert.True( FileValidation.IsValidExtension( "a.png", "jpg,png" ) ); + Assert.True( FileValidation.IsValidExtension( ".jpg", ".jpg,png" ) ); + Assert.True( FileValidation.IsValidExtension( ".png", "jpg,.png" ) ); + Assert.True( FileValidation.IsValidExtension( "a.png", "," ) ); + Assert.False( FileValidation.IsValidExtension( "a.png", ",.jpg" ) ); + Assert.False( FileValidation.IsValidExtension( "a", ",.jpg" ) ); + Assert.True( FileValidation.IsValidExtension( "a", ",." ) ); + } +} \ No newline at end of file diff --git a/test/Util.FileStorage.Tests.Integration/Util.FileStorage.Tests.Integration.csproj b/test/Util.FileStorage.Tests.Integration/Util.FileStorage.Tests.Integration.csproj index 713d6c5d1..5740a1243 100644 --- a/test/Util.FileStorage.Tests.Integration/Util.FileStorage.Tests.Integration.csproj +++ b/test/Util.FileStorage.Tests.Integration/Util.FileStorage.Tests.Integration.csproj @@ -39,7 +39,7 @@ - +