committed by
GitHub
85 changed files with 1513 additions and 433 deletions
@ -0,0 +1,106 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import type { BlobDto } from '../../types/blobs'; |
||||
|
|
||||
|
import { defineAsyncComponent, ref } from 'vue'; |
||||
|
|
||||
|
import { useVbenModal } from '@vben/common-ui'; |
||||
|
import { downloadFileFromUrl } from '@vben/utils'; |
||||
|
|
||||
|
import { Button, Spin } from 'ant-design-vue'; |
||||
|
|
||||
|
import { useBlobsApi } from '../../api/useBlobsApi'; |
||||
|
|
||||
|
const VueFilesPreview = defineAsyncComponent({ |
||||
|
loader: async () => { |
||||
|
const res = await import('vue-files-preview'); |
||||
|
import('vue-files-preview/lib/style.css'); |
||||
|
return res.VueFilesPreview; |
||||
|
}, |
||||
|
loadingComponent: Spin, |
||||
|
delay: 200, |
||||
|
}); |
||||
|
|
||||
|
const fileName = ref<string>(); |
||||
|
const previewUrl = ref<string>(); |
||||
|
const errorMsg = ref<string>(); |
||||
|
|
||||
|
const { generatePreviewUrlApi } = useBlobsApi(); |
||||
|
|
||||
|
const [Modal, modalApi] = useVbenModal({ |
||||
|
showCancelButton: false, |
||||
|
showConfirmButton: false, |
||||
|
fullscreen: true, |
||||
|
fullscreenButton: false, |
||||
|
onOpenChange: async (isOpen) => { |
||||
|
isOpen && onInit(); |
||||
|
}, |
||||
|
onClosed() { |
||||
|
previewUrl.value = undefined; |
||||
|
fileName.value = undefined; |
||||
|
errorMsg.value = undefined; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
async function onInit() { |
||||
|
try { |
||||
|
modalApi.lock(); |
||||
|
const blob = modalApi.getData<BlobDto>(); |
||||
|
fileName.value = blob.name; |
||||
|
previewUrl.value = await generatePreviewUrlApi(blob.id); |
||||
|
} finally { |
||||
|
modalApi.unlock(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async function handleDownload() { |
||||
|
downloadFileFromUrl({ |
||||
|
fileName: fileName.value!, |
||||
|
source: previewUrl.value!, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function onError(error: Error) { |
||||
|
errorMsg.value = error.message; |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<Modal :title="fileName"> |
||||
|
<div class="preview-container"> |
||||
|
<VueFilesPreview |
||||
|
v-if="previewUrl" |
||||
|
:url="previewUrl" |
||||
|
:name="fileName" |
||||
|
@error="onError" |
||||
|
/> |
||||
|
|
||||
|
<!-- 下载按钮 --> |
||||
|
<div v-if="errorMsg && previewUrl" class="download-button"> |
||||
|
<Button type="primary" @click="handleDownload"> |
||||
|
{{ $t('BlobManagement.Blobs:Download') }} |
||||
|
</Button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</Modal> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.preview-container { |
||||
|
position: relative; |
||||
|
height: 100%; |
||||
|
|
||||
|
.error-message { |
||||
|
padding: 40px 20px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.download-button { |
||||
|
position: sticky; |
||||
|
right: 20px; |
||||
|
bottom: 20px; |
||||
|
z-index: 10; |
||||
|
float: right; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -1,34 +0,0 @@ |
|||||
using Aliyun.Acs.Core; |
|
||||
using Aliyun.Acs.Core.Auth; |
|
||||
using Aliyun.Acs.Core.Profile; |
|
||||
using LINGYUN.Abp.Aliyun.Features; |
|
||||
using Volo.Abp.Caching; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.Features; |
|
||||
using Volo.Abp.Settings; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Aliyun; |
|
||||
|
|
||||
[RequiresFeature(AliyunFeatureNames.Enable)] |
|
||||
public class AcsClientFactory : AliyunClientFactory<IAcsClient>, IAcsClientFactory, ITransientDependency |
|
||||
{ |
|
||||
public AcsClientFactory( |
|
||||
ISettingProvider settingProvider, |
|
||||
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
|
||||
: base(settingProvider, cache) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected override IAcsClient GetClient(string regionId, string accessKeyId, string accessKeySecret) |
|
||||
{ |
|
||||
return new DefaultAcsClient( |
|
||||
DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret)); |
|
||||
} |
|
||||
|
|
||||
protected override IAcsClient GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken) |
|
||||
{ |
|
||||
var profile = DefaultProfile.GetProfile(regionId); |
|
||||
var credentials = new BasicSessionCredentials(accessKeyId, accessKeySecret, securityToken); |
|
||||
return new DefaultAcsClient(profile, credentials); |
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
using Aliyun.Acs.Core; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Aliyun; |
|
||||
|
|
||||
public interface IAcsClientFactory |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 构造一个通用的Acs客户端调用
|
|
||||
/// 通过CommonRequest调用可以不需要集成其他SDK包
|
|
||||
/// </summary>
|
|
||||
/// <returns></returns>
|
|
||||
Task<IAcsClient> CreateAsync(); |
|
||||
} |
|
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.Net.Http; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection; |
||||
|
internal static class AliyunHttpClientFactoryServiceCollectionExtensions |
||||
|
{ |
||||
|
private const string HttpClientName = "__AliyunBlobStoringApiClient"; |
||||
|
public static IServiceCollection AddAliyunHttpClient(this IServiceCollection services) |
||||
|
{ |
||||
|
services.AddHttpClient(HttpClientName); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
public static HttpClient CreateAliyunHttpClient(this IHttpClientFactory httpClientFactory) |
||||
|
{ |
||||
|
return httpClientFactory.CreateClient(HttpClientName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using AlibabaCloud.SDK.Dypnsapi20170525; |
||||
|
using LINGYUN.Abp.Aliyun; |
||||
|
using System; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun; |
||||
|
|
||||
|
public class DypnsClientFactory : AliyunClientFactory<Client>, IDypnsClientFactory, ITransientDependency |
||||
|
{ |
||||
|
public DypnsClientFactory( |
||||
|
ISettingProvider settingProvider, |
||||
|
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) |
||||
|
: base(settingProvider, cache) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override Client GetClient(string regionId, string accessKeyId, string accessKeySecret) |
||||
|
{ |
||||
|
return new Client( |
||||
|
new AlibabaCloud.OpenApiClient.Models.Config |
||||
|
{ |
||||
|
RegionId = regionId, |
||||
|
AccessKeyId = accessKeyId, |
||||
|
AccessKeySecret = accessKeySecret, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected override Client GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken, DateTime? expiration = null) |
||||
|
{ |
||||
|
return new Client( |
||||
|
new AlibabaCloud.OpenApiClient.Models.Config |
||||
|
{ |
||||
|
RegionId = regionId, |
||||
|
AccessKeyId = accessKeyId, |
||||
|
AccessKeySecret = accessKeySecret, |
||||
|
SecurityToken = securityToken, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using AlibabaCloud.SDK.Dysmsapi20170525; |
||||
|
using LINGYUN.Abp.Aliyun; |
||||
|
using System; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun; |
||||
|
|
||||
|
public class DysmsClientFactory : AliyunClientFactory<Client>, IDysmsClientFactory, ITransientDependency |
||||
|
{ |
||||
|
public DysmsClientFactory(ISettingProvider settingProvider, IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache) : base(settingProvider, cache) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override Client GetClient(string regionId, string accessKeyId, string accessKeySecret) |
||||
|
{ |
||||
|
return new Client( |
||||
|
new AlibabaCloud.OpenApiClient.Models.Config |
||||
|
{ |
||||
|
RegionId = regionId, |
||||
|
AccessKeyId = accessKeyId, |
||||
|
AccessKeySecret = accessKeySecret, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected override Client GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken, DateTime? expiration = null) |
||||
|
{ |
||||
|
return new Client( |
||||
|
new AlibabaCloud.OpenApiClient.Models.Config |
||||
|
{ |
||||
|
RegionId = regionId, |
||||
|
AccessKeyId = accessKeyId, |
||||
|
AccessKeySecret = accessKeySecret, |
||||
|
SecurityToken = securityToken, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using AlibabaCloud.SDK.Dypnsapi20170525; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun; |
||||
|
|
||||
|
public interface IDypnsClientFactory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 构建短信认证客户端
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
Task<Client> CreateAsync(); |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using AlibabaCloud.SDK.Dysmsapi20170525; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Sms.Aliyun; |
||||
|
|
||||
|
public interface IDysmsClientFactory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 构建短信客户端
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
Task<Client> CreateAsync(); |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement.Dtos; |
||||
|
|
||||
|
public class BlobDownloadByIdInput |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public Guid Id { get; set; } |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public class AbpBlobManagementContentTypeResolveOptions |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public List<IBlobContentTypeResolveContributor> BlobContentTypeResolvers { get; } |
||||
|
|
||||
|
public AbpBlobManagementContentTypeResolveOptions() |
||||
|
{ |
||||
|
BlobContentTypeResolvers = new List<IBlobContentTypeResolveContributor>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public class BlobContentTypeResolveContext |
||||
|
{ |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
public string BlobName { get; } |
||||
|
public Stream Stream { get; } |
||||
|
public bool Handled { get; private set; } |
||||
|
public string? ContentType { get; private set; } |
||||
|
public BlobContentTypeResolveContext( |
||||
|
IServiceProvider serviceProvider, |
||||
|
string blobName, |
||||
|
Stream stream) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
BlobName = blobName; |
||||
|
Stream = stream; |
||||
|
} |
||||
|
|
||||
|
public void Success(string contentType) |
||||
|
{ |
||||
|
ContentType = contentType; |
||||
|
Handled = true; |
||||
|
} |
||||
|
|
||||
|
public bool HasResolvedContentType() |
||||
|
{ |
||||
|
return Handled && !ContentType.IsNullOrWhiteSpace(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public interface IBlobContentTypeResolveContributor |
||||
|
{ |
||||
|
string Name { get; } |
||||
|
int Priority { get; } |
||||
|
Task ResolveAsync(BlobContentTypeResolveContext context); |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public class BlobContentTypeResolver : IBlobContentTypeResolver, ITransientDependency |
||||
|
{ |
||||
|
public ILogger<BlobContentTypeResolver> Logger { get; set; } |
||||
|
|
||||
|
protected IServiceScopeFactory ServiceScopeFactory { get; } |
||||
|
protected AbpBlobManagementContentTypeResolveOptions Options { get; } |
||||
|
|
||||
|
public BlobContentTypeResolver( |
||||
|
IOptions<AbpBlobManagementContentTypeResolveOptions> options, |
||||
|
IServiceScopeFactory serviceScopeFactory) |
||||
|
{ |
||||
|
ServiceScopeFactory = serviceScopeFactory; |
||||
|
Options = options.Value; |
||||
|
|
||||
|
Logger = NullLogger<BlobContentTypeResolver>.Instance; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<string> ResolveContentTypeAsync(string blobName, Stream blobStream) |
||||
|
{ |
||||
|
string? result = null; |
||||
|
|
||||
|
Logger.LogDebug("Starting resolving content type..."); |
||||
|
using (var serviceScope = ServiceScopeFactory.CreateScope()) |
||||
|
{ |
||||
|
var context = new BlobContentTypeResolveContext(serviceScope.ServiceProvider, blobName, blobStream); |
||||
|
|
||||
|
foreach (var blobContentTypeResolver in Options.BlobContentTypeResolvers.OrderByDescending(x => x.Priority)) |
||||
|
{ |
||||
|
var originalPosition = context.Stream.CanSeek ? context.Stream.Position : -1; |
||||
|
|
||||
|
Logger.LogDebug("Trying to resolve content type '{Name}'...", blobContentTypeResolver.Name); |
||||
|
|
||||
|
await blobContentTypeResolver.ResolveAsync(context); |
||||
|
|
||||
|
if (originalPosition >= 0 && context.Stream.CanSeek) |
||||
|
{ |
||||
|
context.Stream.Position = originalPosition; |
||||
|
} |
||||
|
|
||||
|
if (context.HasResolvedContentType()) |
||||
|
{ |
||||
|
result = context.ContentType; |
||||
|
|
||||
|
Logger.LogDebug("Content type resolved by '{Name}' as '{ContentType}'.", blobContentTypeResolver.Name, result); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (result.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
Logger.LogWarning("No provider can resolve content type. Using the default \"application/octet-stream\"."); |
||||
|
|
||||
|
return "application/octet-stream"; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public class BlobDownloadKeyCacheItem |
||||
|
{ |
||||
|
public string Url { get; set; } |
||||
|
public Guid BlobId { get; set; } |
||||
|
public BlobDownloadKeyCacheItem() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public BlobDownloadKeyCacheItem(Guid blobId, string url) |
||||
|
{ |
||||
|
BlobId = blobId; |
||||
|
Url = url; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public interface IBlobContentTypeResolver |
||||
|
{ |
||||
|
Task<string> ResolveContentTypeAsync(string blobName, Stream blobStream); |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using Microsoft.AspNetCore.StaticFiles; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement; |
||||
|
|
||||
|
public class FileExtensionBlobContentTypeResolveContributor : IBlobContentTypeResolveContributor |
||||
|
{ |
||||
|
public string Name => "FileExtension"; |
||||
|
public int Priority => 0; |
||||
|
|
||||
|
public virtual Task ResolveAsync(BlobContentTypeResolveContext context) |
||||
|
{ |
||||
|
var contentTypeProvider = context.ServiceProvider.GetService<IContentTypeProvider>(); |
||||
|
if (contentTypeProvider != null && |
||||
|
contentTypeProvider.TryGetContentType(context.BlobName, out var contentType) && |
||||
|
!contentType.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
context.Success(contentType); |
||||
|
} |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,25 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net10.0</TargetFramework> |
||||
|
<AssemblyName>LINGYUN.Abp.BlobManagement.MimeCheck</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.BlobManagement.MimeCheck</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="MimeCheck" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.BlobManagement.Domain\LINGYUN.Abp.BlobManagement.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement.MimeCheck; |
||||
|
|
||||
|
[DependsOn(typeof(AbpBlobManagementDomainModule))] |
||||
|
public class AbpBlobManagementMimeCheckModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpBlobManagementContentTypeResolveOptions>(options => |
||||
|
{ |
||||
|
options.BlobContentTypeResolvers.Add(new MimeCheckBlobContentTypeResolveContributor()); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using MimeCheck.Detection; |
||||
|
using MimeCheck.Validation; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobManagement.MimeCheck; |
||||
|
|
||||
|
public class MimeCheckBlobContentTypeResolveContributor : IBlobContentTypeResolveContributor |
||||
|
{ |
||||
|
public string Name => "MimeCheck"; |
||||
|
public int Priority => 200; |
||||
|
|
||||
|
public async virtual Task ResolveAsync(BlobContentTypeResolveContext context) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var streamResult = await MimeValidator.DetectAsync(context.Stream); |
||||
|
if (!streamResult.MimeType.IsNullOrWhiteSpace() && |
||||
|
!string.Equals(streamResult.MimeType, DetectionResult.Unknown.MimeType)) |
||||
|
{ |
||||
|
context.Success(streamResult.MimeType); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
context.ServiceProvider |
||||
|
.GetService<ILogger<MimeCheckBlobContentTypeResolveContributor>>() |
||||
|
?.LogWarning("Failed to decetion the blob mime type: {message}!", ex.Message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue