committed by
GitHub
38 changed files with 1434 additions and 1403 deletions
@ -1,13 +1,18 @@ |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpLocalizationDynamicModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpLocalizationDynamicModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddHostedService<DynamicLocalizationInitializeService>(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,22 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class AbpLocalizationDynamicOptions |
|||
{ |
|||
internal LocalizationDictionary LocalizationDictionary { get; } |
|||
|
|||
public AbpLocalizationDynamicOptions() |
|||
{ |
|||
LocalizationDictionary = new LocalizationDictionary(); |
|||
} |
|||
|
|||
internal void AddOrUpdate(string resourceName, Dictionary<string, ILocalizationDictionary> dictionares) |
|||
{ |
|||
var _dictionares = LocalizationDictionary |
|||
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
_dictionares.AddIfNotContains(dictionares); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationInitializeService : IHostedService |
|||
{ |
|||
protected ILocalizationStore Store { get; } |
|||
protected AbpLocalizationOptions LocalizationOptions { get; } |
|||
protected AbpLocalizationDynamicOptions DynamicOptions { get; } |
|||
|
|||
public DynamicLocalizationInitializeService( |
|||
ILocalizationStore store, |
|||
IOptions<AbpLocalizationOptions> localizationOptions, |
|||
IOptions<AbpLocalizationDynamicOptions> dynamicOptions) |
|||
{ |
|||
Store = store; |
|||
DynamicOptions = dynamicOptions.Value; |
|||
LocalizationOptions = localizationOptions.Value; |
|||
} |
|||
|
|||
public virtual async Task StartAsync(CancellationToken cancellationToken) |
|||
{ |
|||
foreach (var resource in LocalizationOptions.Resources) |
|||
{ |
|||
foreach (var contributor in resource.Value.Contributors) |
|||
{ |
|||
if (contributor.GetType().IsAssignableFrom(typeof(DynamicLocalizationResourceContributor))) |
|||
{ |
|||
var resourceLocalizationDic = await Store.GetLocalizationDictionaryAsync(resource.Value.ResourceName); |
|||
DynamicOptions.AddOrUpdate(resource.Value.ResourceName, resourceLocalizationDic); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public Task StopAsync(CancellationToken cancellationToken) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -1,120 +1,41 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Nito.AsyncEx; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor |
|||
{ |
|||
private ILogger _logger; |
|||
private ILocalizationSubscriber _subscriber; |
|||
|
|||
private ILocalizationStore _store; |
|||
protected ILocalizationStore Store => _store; |
|||
|
|||
private Dictionary<string, ILocalizationDictionary> _dictionaries; |
|||
|
|||
private readonly string _resourceName; |
|||
private readonly AsyncLock _asyncLock = new AsyncLock(); |
|||
|
|||
public DynamicLocalizationResourceContributor(string resourceName) |
|||
{ |
|||
_resourceName = resourceName; |
|||
} |
|||
|
|||
public virtual void Initialize(LocalizationResourceInitializationContext context) |
|||
{ |
|||
_logger = context.ServiceProvider.GetService<ILogger<DynamicLocalizationResourceContributor>>(); |
|||
|
|||
_store = context.ServiceProvider.GetRequiredService<ILocalizationStore>(); |
|||
_subscriber = context.ServiceProvider.GetRequiredService<ILocalizationSubscriber>(); |
|||
_subscriber.Subscribe(OnChanged); |
|||
} |
|||
|
|||
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
|||
{ |
|||
GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); |
|||
} |
|||
|
|||
public virtual LocalizedString GetOrNull(string cultureName, string name) |
|||
{ |
|||
return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries() |
|||
{ |
|||
var dictionaries = _dictionaries; |
|||
if (dictionaries != null) |
|||
{ |
|||
return dictionaries; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
using (_asyncLock.Lock()) |
|||
{ |
|||
dictionaries = _dictionaries = AsyncHelper.RunSync(async () => |
|||
await Store.GetLocalizationDictionaryAsync(_resourceName)); |
|||
} |
|||
} |
|||
catch(Exception ex) |
|||
{ |
|||
// 错误不应该影响到应用程序,而是记录到日志
|
|||
_logger?.LogWarning("Failed to get localized text, error: ", ex.Message); |
|||
} |
|||
|
|||
return dictionaries; |
|||
} |
|||
|
|||
private Task OnChanged(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
if (string.Equals(_resourceName, data.ResourceName)) |
|||
{ |
|||
if (!_dictionaries.ContainsKey(data.CultureName)) |
|||
{ |
|||
// TODO: 需要处理 data.Key data.Value 空引用
|
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
_dictionaries.Add(data.CultureName, newLocalizationDictionary); |
|||
} |
|||
else |
|||
{ |
|||
// 取出当前的缓存写入到新字典进行处理
|
|||
var nowLocalizationDictionary = _dictionaries[data.CultureName]; |
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
nowLocalizationDictionary.Fill(dictionary); |
|||
|
|||
var existsKey = dictionary.ContainsKey(data.Key); |
|||
if (!existsKey) |
|||
{ |
|||
// 如果不存在,则新增
|
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
} |
|||
else if (existsKey && data.IsDeleted) |
|||
{ |
|||
// 如果删掉了本地化的节点,删掉当前的缓存
|
|||
dictionary.Remove(data.Key); |
|||
} |
|||
|
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
if (newLocalizationDictionary != null) |
|||
{ |
|||
// 重新赋值变更过的缓存
|
|||
_dictionaries[data.CultureName] = newLocalizationDictionary; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor |
|||
{ |
|||
private readonly string _resourceName; |
|||
|
|||
private AbpLocalizationDynamicOptions _options; |
|||
|
|||
public DynamicLocalizationResourceContributor(string resourceName) |
|||
{ |
|||
_resourceName = resourceName; |
|||
} |
|||
|
|||
public virtual void Initialize(LocalizationResourceInitializationContext context) |
|||
{ |
|||
_options = context.ServiceProvider.GetService<IOptions<AbpLocalizationDynamicOptions>>().Value; |
|||
} |
|||
|
|||
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
|||
{ |
|||
GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); |
|||
} |
|||
|
|||
public virtual LocalizedString GetOrNull(string cultureName, string name) |
|||
{ |
|||
return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries() |
|||
{ |
|||
return _options.LocalizationDictionary |
|||
.GetOrAdd(_resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,14 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal interface ILocalizationDispatcher |
|||
{ |
|||
/// <summary>
|
|||
/// 发布变更事件
|
|||
/// </summary>
|
|||
/// <param name="data"></param>
|
|||
/// <returns></returns>
|
|||
Task DispatchAsync(LocalizedStringCacheResetEventData data); |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
/// <summary>
|
|||
/// 本地化资源订阅
|
|||
/// </summary>
|
|||
internal interface ILocalizationSubscriber |
|||
{ |
|||
/// <summary>
|
|||
/// 订阅变更事件
|
|||
/// </summary>
|
|||
/// <param name="func"></param>
|
|||
void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class LocalizationDictionary : Dictionary<string, Dictionary<string, ILocalizationDictionary>> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,23 +1,72 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal class LocalizationResetSynchronizer : |
|||
IDistributedEventHandler<LocalizedStringCacheResetEventData>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly ILocalizationDispatcher _dispatcher; |
|||
|
|||
public LocalizationResetSynchronizer( |
|||
ILocalizationDispatcher dispatcher) |
|||
{ |
|||
_dispatcher = dispatcher; |
|||
} |
|||
public async Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) |
|||
{ |
|||
await _dispatcher.DispatchAsync(eventData); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal class LocalizationResetSynchronizer : |
|||
IDistributedEventHandler<LocalizedStringCacheResetEventData>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly AbpLocalizationDynamicOptions _options; |
|||
|
|||
public LocalizationResetSynchronizer( |
|||
IOptions<AbpLocalizationDynamicOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
} |
|||
public virtual Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) |
|||
{ |
|||
var dictionaries = GetDictionaries(eventData.ResourceName); |
|||
if (!dictionaries.ContainsKey(eventData.CultureName)) |
|||
{ |
|||
// TODO: 需要处理 data.Key data.Value 空引用
|
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); |
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); |
|||
|
|||
dictionaries.Add(eventData.CultureName, newLocalizationDictionary); |
|||
} |
|||
else |
|||
{ |
|||
// 取出当前的缓存写入到新字典进行处理
|
|||
var nowLocalizationDictionary = dictionaries[eventData.CultureName]; |
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
nowLocalizationDictionary.Fill(dictionary); |
|||
|
|||
var existsKey = dictionary.ContainsKey(eventData.Key); |
|||
if (!existsKey) |
|||
{ |
|||
// 如果不存在,则新增
|
|||
dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); |
|||
} |
|||
else if (existsKey && eventData.IsDeleted) |
|||
{ |
|||
// 如果删掉了本地化的节点,删掉当前的缓存
|
|||
dictionary.Remove(eventData.Key); |
|||
} |
|||
|
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); |
|||
|
|||
if (newLocalizationDictionary != null) |
|||
{ |
|||
// 重新赋值变更过的缓存
|
|||
dictionaries[eventData.CultureName] = newLocalizationDictionary; |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries(string resourceName) |
|||
{ |
|||
return _options.LocalizationDictionary |
|||
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,33 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[ExposeServices( |
|||
typeof(ILocalizationSubscriber), |
|||
typeof(ILocalizationDispatcher), |
|||
typeof(LocalizationSubscriber))] |
|||
internal class LocalizationSubscriber : ILocalizationSubscriber, ILocalizationDispatcher, ISingletonDependency |
|||
{ |
|||
private Func<LocalizedStringCacheResetEventData, Task> _handler; |
|||
|
|||
public LocalizationSubscriber() |
|||
{ |
|||
_handler = (d) => |
|||
{ |
|||
return Task.CompletedTask; |
|||
}; |
|||
} |
|||
|
|||
public void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func) |
|||
{ |
|||
_handler += func; |
|||
} |
|||
|
|||
public virtual async Task DispatchAsync(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
await _handler(data); |
|||
} |
|||
} |
|||
} |
|||
@ -1,369 +1,370 @@ |
|||
using Aliyun.OSS; |
|||
using LINGYUN.Abp.BlobStoring.Aliyun; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.Aliyun |
|||
{ |
|||
/// <summary>
|
|||
/// Oss容器的阿里云实现
|
|||
/// </summary>
|
|||
internal class AliyunOssContainer : IOssContainer |
|||
{ |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
protected IOssClientFactory OssClientFactory { get; } |
|||
public AliyunOssContainer( |
|||
ICurrentTenant currentTenant, |
|||
IOssClientFactory ossClientFactory) |
|||
{ |
|||
CurrentTenant = currentTenant; |
|||
OssClientFactory = ossClientFactory; |
|||
} |
|||
public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var path = GetBasePath(request.Path); |
|||
var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList()); |
|||
|
|||
ossClient.DeleteObjects(aliyunRequest); |
|||
} |
|||
|
|||
public virtual async Task<OssContainer> CreateAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
if (BucketExists(ossClient, name)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists); |
|||
} |
|||
|
|||
var bucket = ossClient.CreateBucket(name); |
|||
|
|||
return new OssContainer( |
|||
bucket.Name, |
|||
bucket.CreationDate, |
|||
0L, |
|||
bucket.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", bucket.Owner?.Id }, |
|||
{ "DisplayName", bucket.Owner?.DisplayName } |
|||
}); |
|||
} |
|||
|
|||
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
|
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists); |
|||
} |
|||
|
|||
// 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在
|
|||
// 详情见:https://help.aliyun.com/document_detail/31910.html
|
|||
if (objectName.EndsWith("/") && |
|||
request.Content.IsNullOrEmpty()) |
|||
{ |
|||
var emptyStream = new MemoryStream(); |
|||
var emptyData = System.Text.Encoding.UTF8.GetBytes(""); |
|||
await emptyStream.WriteAsync(emptyData, 0, emptyData.Length); |
|||
request.SetContent(emptyStream); |
|||
} |
|||
|
|||
// 没有bucket则创建
|
|||
if (!BucketExists(ossClient, request.Bucket)) |
|||
{ |
|||
ossClient.CreateBucket(request.Bucket); |
|||
} |
|||
|
|||
var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content) |
|||
{ |
|||
Metadata = new ObjectMetadata() |
|||
}; |
|||
if (request.ExpirationTime.HasValue) |
|||
{ |
|||
aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value); |
|||
} |
|||
|
|||
var aliyunObject = ossClient.PutObject(aliyunObjectRequest); |
|||
|
|||
var ossObject = new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() |
|||
? objectName.Replace(objectPath, "") |
|||
: objectName, |
|||
objectPath, |
|||
DateTime.Now, |
|||
aliyunObject.ContentLength, |
|||
DateTime.Now, |
|||
aliyunObject.ResponseMetadata, |
|||
objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html
|
|||
) |
|||
{ |
|||
FullName = objectName |
|||
}; |
|||
|
|||
if (!Equals(request.Content, Stream.Null)) |
|||
{ |
|||
request.Content.Seek(0, SeekOrigin.Begin); |
|||
ossObject.SetContent(request.Content); |
|||
} |
|||
|
|||
return ossObject; |
|||
} |
|||
|
|||
public virtual async Task DeleteAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
if (BucketExists(ossClient, name)) |
|||
{ |
|||
ossClient.DeleteBucket(name); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task DeleteObjectAsync(GetOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
|
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (BucketExists(ossClient, request.Bucket) && |
|||
ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
var objectListing = ossClient.ListObjects(request.Bucket, objectName); |
|||
if (objectListing.CommonPrefixes.Any() || |
|||
objectListing.ObjectSummaries.Any()) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty); |
|||
// throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!");
|
|||
} |
|||
ossClient.DeleteObject(request.Bucket, objectName); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task<bool> ExistsAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
return BucketExists(ossClient, name); |
|||
} |
|||
|
|||
public virtual async Task<OssContainer> GetAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
if (!BucketExists(ossClient, name)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing");
|
|||
} |
|||
var bucket = ossClient.GetBucketInfo(name); |
|||
|
|||
return new OssContainer( |
|||
bucket.Bucket.Name, |
|||
bucket.Bucket.CreationDate, |
|||
0L, |
|||
bucket.Bucket.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", bucket.Bucket.Owner?.Id }, |
|||
{ "DisplayName", bucket.Bucket.Owner?.DisplayName } |
|||
}); |
|||
} |
|||
|
|||
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
if (!BucketExists(ossClient, request.Bucket)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing");
|
|||
} |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (!ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing");
|
|||
} |
|||
|
|||
var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process); |
|||
var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest); |
|||
var ossObject = new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() |
|||
? aliyunOssObject.Key.Replace(objectPath, "") |
|||
: aliyunOssObject.Key, |
|||
request.Path, |
|||
aliyunOssObject.Metadata.LastModified, |
|||
aliyunOssObject.Metadata.ContentLength, |
|||
aliyunOssObject.Metadata.LastModified, |
|||
aliyunOssObject.Metadata.UserMetadata, |
|||
aliyunOssObject.Key.EndsWith("/")) |
|||
{ |
|||
FullName = aliyunOssObject.Key |
|||
}; |
|||
|
|||
if (aliyunOssObject.IsSetResponseStream()) |
|||
{ |
|||
var memoryStream = new MemoryStream(); |
|||
await aliyunOssObject.Content.CopyToAsync(memoryStream); |
|||
memoryStream.Seek(0, SeekOrigin.Begin); |
|||
ossObject.SetContent(memoryStream); |
|||
} |
|||
|
|||
return ossObject; |
|||
} |
|||
|
|||
public virtual async Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var aliyunRequest = new ListBucketsRequest |
|||
{ |
|||
Marker = request.Marker, |
|||
Prefix = request.Prefix, |
|||
MaxKeys = request.MaxKeys |
|||
}; |
|||
var bucketsResponse = ossClient.ListBuckets(aliyunRequest); |
|||
|
|||
return new GetOssContainersResponse( |
|||
bucketsResponse.Prefix, |
|||
bucketsResponse.Marker, |
|||
bucketsResponse.NextMaker, |
|||
bucketsResponse.MaxKeys ?? 0, |
|||
bucketsResponse.Buckets |
|||
.Select(x => new OssContainer( |
|||
x.Name, |
|||
x.CreationDate, |
|||
0L, |
|||
x.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", x.Owner?.Id }, |
|||
{ "DisplayName", x.Owner?.DisplayName } |
|||
})) |
|||
.ToList()); |
|||
} |
|||
|
|||
public virtual async Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request) |
|||
{ |
|||
|
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Prefix); |
|||
var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace() |
|||
? request.Marker.Replace(objectPath, "") |
|||
: request.Marker; |
|||
var aliyunRequest = new ListObjectsRequest(request.BucketName) |
|||
{ |
|||
Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker, |
|||
Prefix = objectPath, |
|||
MaxKeys = request.MaxKeys, |
|||
EncodingType = request.EncodingType, |
|||
Delimiter = request.Delimiter |
|||
}; |
|||
var objectsResponse = ossClient.ListObjects(aliyunRequest); |
|||
|
|||
var ossObjects = objectsResponse.ObjectSummaries |
|||
.Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值
|
|||
.Select(x => new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath) |
|||
? x.Key.Replace(objectPath, "") |
|||
: x.Key, // 去除目录名称
|
|||
request.Prefix, |
|||
x.LastModified, |
|||
x.Size, |
|||
x.LastModified, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", x.Owner?.Id }, |
|||
{ "DisplayName", x.Owner?.DisplayName } |
|||
}, |
|||
x.Key.EndsWith("/")) |
|||
{ |
|||
FullName = x.Key |
|||
}) |
|||
.ToList(); |
|||
// 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录
|
|||
if (objectsResponse.CommonPrefixes.Any()) |
|||
{ |
|||
ossObjects.InsertRange(0, |
|||
objectsResponse.CommonPrefixes |
|||
.Select(x => new OssObject( |
|||
x.Replace(objectPath, ""), |
|||
request.Prefix, |
|||
null, |
|||
0L, |
|||
null, |
|||
null, |
|||
true))); |
|||
} |
|||
// 排序
|
|||
// TODO: 是否需要客户端来排序
|
|||
ossObjects.Sort(new OssObjectComparer()); |
|||
|
|||
return new GetOssObjectsResponse( |
|||
objectsResponse.BucketName, |
|||
request.Prefix, |
|||
marker, |
|||
!objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace() |
|||
? objectsResponse.NextMarker.Replace(objectPath, "") |
|||
: objectsResponse.NextMarker, |
|||
objectsResponse.Delimiter, |
|||
objectsResponse.MaxKeys, |
|||
ossObjects); |
|||
} |
|||
|
|||
protected virtual string GetBasePath(string path) |
|||
{ |
|||
string objectPath = ""; |
|||
if (CurrentTenant.Id == null) |
|||
{ |
|||
objectPath += "host/"; |
|||
} |
|||
else |
|||
{ |
|||
objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D"); |
|||
} |
|||
|
|||
objectPath += path ?? ""; |
|||
|
|||
return objectPath.EnsureEndsWith('/'); |
|||
} |
|||
|
|||
protected virtual bool BucketExists(IOss client, string bucketName) |
|||
{ |
|||
return client.DoesBucketExist(bucketName); |
|||
} |
|||
|
|||
protected virtual bool ObjectExists(IOss client, string bucketName, string objectName) |
|||
{ |
|||
return client.DoesObjectExist(bucketName, objectName); |
|||
} |
|||
|
|||
protected virtual async Task<IOss> CreateClientAsync() |
|||
{ |
|||
return await OssClientFactory.CreateAsync<AbpOssManagementContainer>(); |
|||
} |
|||
} |
|||
} |
|||
using Aliyun.OSS; |
|||
using LINGYUN.Abp.BlobStoring.Aliyun; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.Aliyun |
|||
{ |
|||
/// <summary>
|
|||
/// Oss容器的阿里云实现
|
|||
/// </summary>
|
|||
internal class AliyunOssContainer : IOssContainer |
|||
{ |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
protected IOssClientFactory OssClientFactory { get; } |
|||
public AliyunOssContainer( |
|||
ICurrentTenant currentTenant, |
|||
IOssClientFactory ossClientFactory) |
|||
{ |
|||
CurrentTenant = currentTenant; |
|||
OssClientFactory = ossClientFactory; |
|||
} |
|||
public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var path = GetBasePath(request.Path); |
|||
var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList()); |
|||
|
|||
ossClient.DeleteObjects(aliyunRequest); |
|||
} |
|||
|
|||
public virtual async Task<OssContainer> CreateAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
if (BucketExists(ossClient, name)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists); |
|||
} |
|||
|
|||
var bucket = ossClient.CreateBucket(name); |
|||
|
|||
return new OssContainer( |
|||
bucket.Name, |
|||
bucket.CreationDate, |
|||
0L, |
|||
bucket.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", bucket.Owner?.Id }, |
|||
{ "DisplayName", bucket.Owner?.DisplayName } |
|||
}); |
|||
} |
|||
|
|||
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
|
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists); |
|||
} |
|||
|
|||
// 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在
|
|||
// 详情见:https://help.aliyun.com/document_detail/31910.html
|
|||
if (objectName.EndsWith("/") && |
|||
request.Content.IsNullOrEmpty()) |
|||
{ |
|||
var emptyStream = new MemoryStream(); |
|||
var emptyData = System.Text.Encoding.UTF8.GetBytes(""); |
|||
await emptyStream.WriteAsync(emptyData, 0, emptyData.Length); |
|||
request.SetContent(emptyStream); |
|||
} |
|||
|
|||
// 没有bucket则创建
|
|||
if (!BucketExists(ossClient, request.Bucket)) |
|||
{ |
|||
ossClient.CreateBucket(request.Bucket); |
|||
} |
|||
|
|||
var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content) |
|||
{ |
|||
Metadata = new ObjectMetadata() |
|||
}; |
|||
if (request.ExpirationTime.HasValue) |
|||
{ |
|||
aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value); |
|||
} |
|||
|
|||
var aliyunObject = ossClient.PutObject(aliyunObjectRequest); |
|||
|
|||
var ossObject = new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() |
|||
? objectName.Replace(objectPath, "") |
|||
: objectName, |
|||
objectPath, |
|||
DateTime.Now, |
|||
aliyunObject.ContentLength, |
|||
DateTime.Now, |
|||
aliyunObject.ResponseMetadata, |
|||
objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html
|
|||
) |
|||
{ |
|||
FullName = objectName |
|||
}; |
|||
|
|||
if (!Equals(request.Content, Stream.Null)) |
|||
{ |
|||
request.Content.Seek(0, SeekOrigin.Begin); |
|||
ossObject.SetContent(request.Content); |
|||
} |
|||
|
|||
return ossObject; |
|||
} |
|||
|
|||
public virtual async Task DeleteAsync(string name) |
|||
{ |
|||
// 阿里云oss在控制台设置即可,无需改变
|
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
if (BucketExists(ossClient, name)) |
|||
{ |
|||
ossClient.DeleteBucket(name); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task DeleteObjectAsync(GetOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
|
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (BucketExists(ossClient, request.Bucket) && |
|||
ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
var objectListing = ossClient.ListObjects(request.Bucket, objectName); |
|||
if (objectListing.CommonPrefixes.Any() || |
|||
objectListing.ObjectSummaries.Any()) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty); |
|||
// throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!");
|
|||
} |
|||
ossClient.DeleteObject(request.Bucket, objectName); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task<bool> ExistsAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
return BucketExists(ossClient, name); |
|||
} |
|||
|
|||
public virtual async Task<OssContainer> GetAsync(string name) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
if (!BucketExists(ossClient, name)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing");
|
|||
} |
|||
var bucket = ossClient.GetBucketInfo(name); |
|||
|
|||
return new OssContainer( |
|||
bucket.Bucket.Name, |
|||
bucket.Bucket.CreationDate, |
|||
0L, |
|||
bucket.Bucket.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", bucket.Bucket.Owner?.Id }, |
|||
{ "DisplayName", bucket.Bucket.Owner?.DisplayName } |
|||
}); |
|||
} |
|||
|
|||
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
if (!BucketExists(ossClient, request.Bucket)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing");
|
|||
} |
|||
|
|||
var objectPath = GetBasePath(request.Path); |
|||
var objectName = objectPath.IsNullOrWhiteSpace() |
|||
? request.Object |
|||
: objectPath + request.Object; |
|||
|
|||
if (!ObjectExists(ossClient, request.Bucket, objectName)) |
|||
{ |
|||
throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound); |
|||
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing");
|
|||
} |
|||
|
|||
var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process); |
|||
var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest); |
|||
var ossObject = new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() |
|||
? aliyunOssObject.Key.Replace(objectPath, "") |
|||
: aliyunOssObject.Key, |
|||
request.Path, |
|||
aliyunOssObject.Metadata.LastModified, |
|||
aliyunOssObject.Metadata.ContentLength, |
|||
aliyunOssObject.Metadata.LastModified, |
|||
aliyunOssObject.Metadata.UserMetadata, |
|||
aliyunOssObject.Key.EndsWith("/")) |
|||
{ |
|||
FullName = aliyunOssObject.Key |
|||
}; |
|||
|
|||
if (aliyunOssObject.IsSetResponseStream()) |
|||
{ |
|||
var memoryStream = new MemoryStream(); |
|||
await aliyunOssObject.Content.CopyToAsync(memoryStream); |
|||
memoryStream.Seek(0, SeekOrigin.Begin); |
|||
ossObject.SetContent(memoryStream); |
|||
} |
|||
|
|||
return ossObject; |
|||
} |
|||
|
|||
public virtual async Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request) |
|||
{ |
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var aliyunRequest = new ListBucketsRequest |
|||
{ |
|||
Marker = request.Marker, |
|||
Prefix = request.Prefix, |
|||
MaxKeys = request.MaxKeys |
|||
}; |
|||
var bucketsResponse = ossClient.ListBuckets(aliyunRequest); |
|||
|
|||
return new GetOssContainersResponse( |
|||
bucketsResponse.Prefix, |
|||
bucketsResponse.Marker, |
|||
bucketsResponse.NextMaker, |
|||
bucketsResponse.MaxKeys ?? 0, |
|||
bucketsResponse.Buckets |
|||
.Select(x => new OssContainer( |
|||
x.Name, |
|||
x.CreationDate, |
|||
0L, |
|||
x.CreationDate, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", x.Owner?.Id }, |
|||
{ "DisplayName", x.Owner?.DisplayName } |
|||
})) |
|||
.ToList()); |
|||
} |
|||
|
|||
public virtual async Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request) |
|||
{ |
|||
|
|||
var ossClient = await CreateClientAsync(); |
|||
|
|||
var objectPath = GetBasePath(request.Prefix); |
|||
var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace() |
|||
? request.Marker.Replace(objectPath, "") |
|||
: request.Marker; |
|||
var aliyunRequest = new ListObjectsRequest(request.BucketName) |
|||
{ |
|||
Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker, |
|||
Prefix = objectPath, |
|||
MaxKeys = request.MaxKeys, |
|||
EncodingType = request.EncodingType, |
|||
Delimiter = request.Delimiter |
|||
}; |
|||
var objectsResponse = ossClient.ListObjects(aliyunRequest); |
|||
|
|||
var ossObjects = objectsResponse.ObjectSummaries |
|||
.Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值
|
|||
.Select(x => new OssObject( |
|||
!objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath) |
|||
? x.Key.Replace(objectPath, "") |
|||
: x.Key, // 去除目录名称
|
|||
request.Prefix, |
|||
x.LastModified, |
|||
x.Size, |
|||
x.LastModified, |
|||
new Dictionary<string, string> |
|||
{ |
|||
{ "Id", x.Owner?.Id }, |
|||
{ "DisplayName", x.Owner?.DisplayName } |
|||
}, |
|||
x.Key.EndsWith("/")) |
|||
{ |
|||
FullName = x.Key |
|||
}) |
|||
.ToList(); |
|||
// 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录
|
|||
if (objectsResponse.CommonPrefixes.Any()) |
|||
{ |
|||
ossObjects.InsertRange(0, |
|||
objectsResponse.CommonPrefixes |
|||
.Select(x => new OssObject( |
|||
x.Replace(objectPath, ""), |
|||
request.Prefix, |
|||
null, |
|||
0L, |
|||
null, |
|||
null, |
|||
true))); |
|||
} |
|||
// 排序
|
|||
// TODO: 是否需要客户端来排序
|
|||
ossObjects.Sort(new OssObjectComparer()); |
|||
|
|||
return new GetOssObjectsResponse( |
|||
objectsResponse.BucketName, |
|||
request.Prefix, |
|||
marker, |
|||
!objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace() |
|||
? objectsResponse.NextMarker.Replace(objectPath, "") |
|||
: objectsResponse.NextMarker, |
|||
objectsResponse.Delimiter, |
|||
objectsResponse.MaxKeys, |
|||
ossObjects); |
|||
} |
|||
|
|||
protected virtual string GetBasePath(string path) |
|||
{ |
|||
string objectPath = ""; |
|||
if (CurrentTenant.Id == null) |
|||
{ |
|||
objectPath += "host/"; |
|||
} |
|||
else |
|||
{ |
|||
objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D"); |
|||
} |
|||
|
|||
objectPath += path ?? ""; |
|||
|
|||
return objectPath.EnsureEndsWith('/'); |
|||
} |
|||
|
|||
protected virtual bool BucketExists(IOss client, string bucketName) |
|||
{ |
|||
return client.DoesBucketExist(bucketName); |
|||
} |
|||
|
|||
protected virtual bool ObjectExists(IOss client, string bucketName, string objectName) |
|||
{ |
|||
return client.DoesObjectExist(bucketName, objectName); |
|||
} |
|||
|
|||
protected virtual async Task<IOss> CreateClientAsync() |
|||
{ |
|||
return await OssClientFactory.CreateAsync<AbpOssManagementContainer>(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,12 +1,12 @@ |
|||
using Volo.Abp.Application; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementDomainSharedModule), |
|||
typeof(AbpDddApplicationModule))] |
|||
public class AbpOssManagementApplicationContractsModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
using Volo.Abp.Application; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementDomainSharedModule), |
|||
typeof(AbpDddApplicationContractsModule))] |
|||
public class AbpOssManagementApplicationContractsModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
|
|||
@ -1,23 +1,27 @@ |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Modularity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAutoMapperModule), |
|||
typeof(AbpOssManagementDomainModule), |
|||
typeof(AbpOssManagementApplicationContractsModule))] |
|||
public class AbpOssManagementApplicationModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAutoMapperObjectMapper<AbpOssManagementApplicationModule>(); |
|||
|
|||
Configure<AbpAutoMapperOptions>(options => |
|||
{ |
|||
options.AddProfile<OssManagementApplicationAutoMapperProfile>(validate: true); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Application; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementDomainModule), |
|||
typeof(AbpOssManagementApplicationContractsModule), |
|||
typeof(AbpCachingModule), |
|||
typeof(AbpAutoMapperModule), |
|||
typeof(AbpDddApplicationModule))] |
|||
public class AbpOssManagementApplicationModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAutoMapperObjectMapper<AbpOssManagementApplicationModule>(); |
|||
|
|||
Configure<AbpAutoMapperOptions>(options => |
|||
{ |
|||
options.AddProfile<OssManagementApplicationAutoMapperProfile>(validate: true); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,14 +1,14 @@ |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public class OssManagementApplicationServiceBase : ApplicationService |
|||
{ |
|||
protected OssManagementApplicationServiceBase() |
|||
{ |
|||
LocalizationResource = typeof(AbpOssManagementResource); |
|||
ObjectMapperContext = typeof(AbpOssManagementApplicationModule); |
|||
} |
|||
} |
|||
} |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public abstract class OssManagementApplicationServiceBase : ApplicationService |
|||
{ |
|||
protected OssManagementApplicationServiceBase() |
|||
{ |
|||
LocalizationResource = typeof(AbpOssManagementResource); |
|||
ObjectMapperContext = typeof(AbpOssManagementApplicationModule); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,116 +1,101 @@ |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using LINGYUN.Abp.OssManagement.Features; |
|||
using LINGYUN.Abp.OssManagement.Permissions; |
|||
using LINGYUN.Abp.OssManagement.Settings; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.IO; |
|||
using Volo.Abp.Settings; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[Authorize(AbpOssManagementPermissions.OssObject.Default)] |
|||
public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService |
|||
{ |
|||
protected IOssContainerFactory OssContainerFactory { get; } |
|||
|
|||
public OssObjectAppService( |
|||
IOssContainerFactory ossContainerFactory) |
|||
{ |
|||
OssContainerFactory = ossContainerFactory; |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Create)] |
|||
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] |
|||
[RequiresLimitFeature( |
|||
AbpOssManagementFeatureNames.OssObject.UploadLimit, |
|||
AbpOssManagementFeatureNames.OssObject.UploadInterval, |
|||
LimitPolicy.Month)] |
|||
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input) |
|||
{ |
|||
if (!input.Content.IsNullOrEmpty()) |
|||
{ |
|||
// 检查文件大小
|
|||
var fileSizeLimited = await SettingProvider |
|||
.GetAsync( |
|||
AbpOssManagementSettingNames.FileLimitLength, |
|||
AbpOssManagementSettingNames.DefaultFileLimitLength); |
|||
if (fileSizeLimited * 1024 * 1024 < input.Content.Length) |
|||
{ |
|||
ThrowValidationException(L["UploadFileSizeBeyondLimit", fileSizeLimited], nameof(input.Content)); |
|||
} |
|||
|
|||
// 文件扩展名
|
|||
var fileExtensionName = FileHelper.GetExtension(input.Object); |
|||
var fileAllowExtension = await SettingProvider.GetOrNullAsync(AbpOssManagementSettingNames.AllowFileExtensions); |
|||
// 检查文件扩展名
|
|||
if (!fileAllowExtension.Split(',') |
|||
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) |
|||
{ |
|||
ThrowValidationException(L["NotAllowedFileExtensionName", fileExtensionName], "FileName"); |
|||
} |
|||
} |
|||
|
|||
var oss = CreateOssContainer(); |
|||
|
|||
var createOssObjectRequest = new CreateOssObjectRequest( |
|||
input.Bucket, |
|||
input.Object, |
|||
input.Content, |
|||
input.Path, |
|||
input.ExpirationTime) |
|||
{ |
|||
Overwrite = input.Overwrite |
|||
}; |
|||
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); |
|||
|
|||
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
|||
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path); |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
|||
public virtual async Task DeleteAsync(GetOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path); |
|||
} |
|||
|
|||
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path); |
|||
|
|||
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
|||
} |
|||
|
|||
protected virtual IOssContainer CreateOssContainer() |
|||
{ |
|||
return OssContainerFactory.Create(); |
|||
} |
|||
|
|||
private static void ThrowValidationException(string message, string memberName) |
|||
{ |
|||
throw new AbpValidationException(message, |
|||
new List<ValidationResult> |
|||
{ |
|||
new ValidationResult(message, new[] {memberName}) |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using LINGYUN.Abp.OssManagement.Features; |
|||
using LINGYUN.Abp.OssManagement.Permissions; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[Authorize(AbpOssManagementPermissions.OssObject.Default)] |
|||
public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService |
|||
{ |
|||
protected IFileValidater FileValidater { get; } |
|||
protected IOssContainerFactory OssContainerFactory { get; } |
|||
|
|||
public OssObjectAppService( |
|||
IFileValidater fileValidater, |
|||
IOssContainerFactory ossContainerFactory) |
|||
{ |
|||
FileValidater = fileValidater; |
|||
OssContainerFactory = ossContainerFactory; |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Create)] |
|||
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] |
|||
[RequiresLimitFeature( |
|||
AbpOssManagementFeatureNames.OssObject.UploadLimit, |
|||
AbpOssManagementFeatureNames.OssObject.UploadInterval, |
|||
LimitPolicy.Month)] |
|||
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input) |
|||
{ |
|||
if (!input.Content.IsNullOrEmpty()) |
|||
{ |
|||
await FileValidater.ValidationAsync(new UploadFile |
|||
{ |
|||
TotalSize = input.Content.Length, |
|||
FileName = input.Object |
|||
}); |
|||
} |
|||
|
|||
var oss = CreateOssContainer(); |
|||
|
|||
var createOssObjectRequest = new CreateOssObjectRequest( |
|||
input.Bucket, |
|||
input.Object, |
|||
input.Content, |
|||
input.Path, |
|||
input.ExpirationTime) |
|||
{ |
|||
Overwrite = input.Overwrite |
|||
}; |
|||
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); |
|||
|
|||
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
|||
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path); |
|||
} |
|||
|
|||
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
|||
public virtual async Task DeleteAsync(GetOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path); |
|||
} |
|||
|
|||
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input) |
|||
{ |
|||
var oss = CreateOssContainer(); |
|||
|
|||
var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path); |
|||
|
|||
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
|||
} |
|||
|
|||
protected virtual IOssContainer CreateOssContainer() |
|||
{ |
|||
return OssContainerFactory.Create(); |
|||
} |
|||
|
|||
private static void ThrowValidationException(string message, string memberName) |
|||
{ |
|||
throw new AbpValidationException(message, |
|||
new List<ValidationResult> |
|||
{ |
|||
new ValidationResult(message, new[] {memberName}) |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,16 @@ |
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public class PublicFileAppService : FileAppServiceBase, IPublicFileAppService |
|||
{ |
|||
public PublicFileAppService( |
|||
IFileValidater fileValidater, |
|||
IOssContainerFactory ossContainerFactory) |
|||
: base(fileValidater, ossContainerFactory) |
|||
{ |
|||
} |
|||
protected override string GetCurrentBucket() |
|||
{ |
|||
return "public"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,36 +1,36 @@ |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Localization.ExceptionHandling; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Validation; |
|||
using Volo.Abp.Validation.Localization; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn(typeof(AbpValidationModule))] |
|||
public class AbpOssManagementDomainSharedModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpOssManagementDomainSharedModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Add<AbpOssManagementResource>("en") |
|||
.AddBaseTypes( |
|||
typeof(AbpValidationResource) |
|||
).AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources"); |
|||
}); |
|||
|
|||
Configure<AbpExceptionLocalizationOptions>(options => |
|||
{ |
|||
options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource)); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Localization.ExceptionHandling; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Validation; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpFeaturesModule), |
|||
typeof(AbpValidationModule))] |
|||
public class AbpOssManagementDomainSharedModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpOssManagementDomainSharedModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Add<AbpOssManagementResource>("en") |
|||
.AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources"); |
|||
}); |
|||
|
|||
Configure<AbpExceptionLocalizationOptions>(options => |
|||
{ |
|||
options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource)); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
0
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs → aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs
0
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs → aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs
@ -1,41 +1,41 @@ |
|||
namespace LINGYUN.Abp.OssManagement.Features |
|||
{ |
|||
public class AbpOssManagementFeatureNames |
|||
{ |
|||
public const string GroupName = "AbpOssManagement"; |
|||
|
|||
|
|||
public class OssObject |
|||
{ |
|||
public const string Default = GroupName + ".OssObject"; |
|||
/// <summary>
|
|||
/// 下载文件功能
|
|||
/// </summary>
|
|||
public const string DownloadFile = Default + ".DownloadFile"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数
|
|||
/// </summary>
|
|||
public const string DownloadLimit = Default + ".DownloadLimit"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string DownloadInterval = Default + ".DownloadInterval"; |
|||
/// <summary>
|
|||
/// 上传文件功能
|
|||
/// </summary>
|
|||
public const string UploadFile = Default + ".UploadFile"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数
|
|||
/// </summary>
|
|||
public const string UploadLimit = Default + ".UploadLimit"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string UploadInterval = Default + ".UploadInterval"; |
|||
/// <summary>
|
|||
/// 最大上传文件
|
|||
/// </summary>
|
|||
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; |
|||
} |
|||
} |
|||
} |
|||
namespace LINGYUN.Abp.OssManagement.Features |
|||
{ |
|||
public class AbpOssManagementFeatureNames |
|||
{ |
|||
public const string GroupName = "AbpOssManagement"; |
|||
|
|||
|
|||
public class OssObject |
|||
{ |
|||
public const string Default = GroupName + ".OssObject"; |
|||
/// <summary>
|
|||
/// 下载文件功能
|
|||
/// </summary>
|
|||
public const string DownloadFile = Default + ".DownloadFile"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数
|
|||
/// </summary>
|
|||
public const string DownloadLimit = Default + ".DownloadLimit"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string DownloadInterval = Default + ".DownloadInterval"; |
|||
/// <summary>
|
|||
/// 上传文件功能
|
|||
/// </summary>
|
|||
public const string UploadFile = Default + ".UploadFile"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数
|
|||
/// </summary>
|
|||
public const string UploadLimit = Default + ".UploadLimit"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string UploadInterval = Default + ".UploadInterval"; |
|||
/// <summary>
|
|||
/// 最大上传文件
|
|||
/// </summary>
|
|||
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,17 +1,18 @@ |
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public static class OssManagementErrorCodes |
|||
{ |
|||
public const string Namespace = "Abp.OssManagement"; |
|||
|
|||
public const string ContainerDeleteWithNotEmpty = Namespace + ":010001"; |
|||
public const string ContainerAlreadyExists = Namespace + ":010402"; |
|||
public const string ContainerNotFound = Namespace + ":010404"; |
|||
|
|||
public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; |
|||
public const string ObjectAlreadyExists = Namespace + ":020402"; |
|||
public const string ObjectNotFound = Namespace + ":020404"; |
|||
|
|||
public const string OssNameHasTooLong = Namespace + ":000405"; |
|||
} |
|||
} |
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public static class OssManagementErrorCodes |
|||
{ |
|||
public const string Namespace = "Abp.OssManagement"; |
|||
|
|||
public const string ContainerDeleteWithStatic = Namespace + ":010000"; |
|||
public const string ContainerDeleteWithNotEmpty = Namespace + ":010001"; |
|||
public const string ContainerAlreadyExists = Namespace + ":010402"; |
|||
public const string ContainerNotFound = Namespace + ":010404"; |
|||
|
|||
public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; |
|||
public const string ObjectAlreadyExists = Namespace + ":020402"; |
|||
public const string ObjectNotFound = Namespace + ":020404"; |
|||
|
|||
public const string OssNameHasTooLong = Namespace + ":000405"; |
|||
} |
|||
} |
|||
|
|||
@ -1,17 +1,32 @@ |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using Volo.Abp.Domain; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpDddDomainModule), |
|||
typeof(AbpMultiTenancyModule), |
|||
typeof(AbpFeaturesLimitValidationModule), |
|||
typeof(AbpOssManagementDomainSharedModule) |
|||
)] |
|||
public class AbpOssManagementDomainModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementDomainSharedModule), |
|||
typeof(AbpDddDomainModule), |
|||
typeof(AbpMultiTenancyModule), |
|||
typeof(AbpFeaturesLimitValidationModule) |
|||
)] |
|||
public class AbpOssManagementDomainModule : AbpModule |
|||
{ |
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
// TODO: 是否有必要自动创建容器
|
|||
var ossOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpOssManagementOptions>>().Value; |
|||
var ossFactory = context.ServiceProvider.GetRequiredService<IOssContainerFactory>(); |
|||
var ossContainer = ossFactory.Create(); |
|||
|
|||
foreach (var bucket in ossOptions.StaticBuckets) |
|||
{ |
|||
_ = ossContainer.CreateIfNotExistsAsync(bucket); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,17 +1,19 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.FileSystem |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpBlobStoringFileSystemModule), |
|||
typeof(AbpOssManagementDomainModule))] |
|||
public class AbpOssManagementFileSystemModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddTransient<IOssContainerFactory, FileSystemOssContainerFactory>(); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.FileSystem |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpBlobStoringFileSystemModule), |
|||
typeof(AbpOssManagementDomainModule))] |
|||
public class AbpOssManagementFileSystemModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddTransient<IOssContainerFactory, FileSystemOssContainerFactory>(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,46 +1,50 @@ |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.FileSystem |
|||
{ |
|||
public class FileSystemOssContainerFactory : IOssContainerFactory |
|||
{ |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
protected IHostEnvironment Environment { get; } |
|||
protected IServiceProvider ServiceProvider { get; } |
|||
protected IBlobFilePathCalculator FilePathCalculator { get; } |
|||
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } |
|||
protected IOptions<FileSystemOssOptions> Options { get; } |
|||
|
|||
public FileSystemOssContainerFactory( |
|||
ICurrentTenant currentTenant, |
|||
IHostEnvironment environment, |
|||
IServiceProvider serviceProvider, |
|||
IBlobFilePathCalculator blobFilePathCalculator, |
|||
IBlobContainerConfigurationProvider configurationProvider, |
|||
IOptions<FileSystemOssOptions> options) |
|||
{ |
|||
Environment = environment; |
|||
CurrentTenant = currentTenant; |
|||
ServiceProvider = serviceProvider; |
|||
FilePathCalculator = blobFilePathCalculator; |
|||
ConfigurationProvider = configurationProvider; |
|||
Options = options; |
|||
} |
|||
|
|||
public IOssContainer Create() |
|||
{ |
|||
return new FileSystemOssContainer( |
|||
CurrentTenant, |
|||
Environment, |
|||
ServiceProvider, |
|||
FilePathCalculator, |
|||
ConfigurationProvider, |
|||
Options); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.FileSystem |
|||
{ |
|||
public class FileSystemOssContainerFactory : IOssContainerFactory |
|||
{ |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
protected IHostEnvironment Environment { get; } |
|||
protected IServiceProvider ServiceProvider { get; } |
|||
protected IBlobFilePathCalculator FilePathCalculator { get; } |
|||
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } |
|||
protected IOptions<FileSystemOssOptions> Options { get; } |
|||
protected IOptions<AbpOssManagementOptions> OssOptions { get; } |
|||
|
|||
public FileSystemOssContainerFactory( |
|||
ICurrentTenant currentTenant, |
|||
IHostEnvironment environment, |
|||
IServiceProvider serviceProvider, |
|||
IBlobFilePathCalculator blobFilePathCalculator, |
|||
IBlobContainerConfigurationProvider configurationProvider, |
|||
IOptions<FileSystemOssOptions> options, |
|||
IOptions<AbpOssManagementOptions> ossOptions) |
|||
{ |
|||
Environment = environment; |
|||
CurrentTenant = currentTenant; |
|||
ServiceProvider = serviceProvider; |
|||
FilePathCalculator = blobFilePathCalculator; |
|||
ConfigurationProvider = configurationProvider; |
|||
Options = options; |
|||
OssOptions = ossOptions; |
|||
} |
|||
|
|||
public IOssContainer Create() |
|||
{ |
|||
return new FileSystemOssContainer( |
|||
CurrentTenant, |
|||
Environment, |
|||
ServiceProvider, |
|||
FilePathCalculator, |
|||
ConfigurationProvider, |
|||
Options, |
|||
OssOptions); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,21 +1,47 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementApplicationContractsModule), |
|||
typeof(AbpAspNetCoreMvcModule) |
|||
)] |
|||
public class AbpOssManagementHttpApiModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Authorization.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Validation.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.DataAnnotations; |
|||
using Volo.Abp.AspNetCore.Mvc.Localization; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementApplicationContractsModule), |
|||
typeof(AbpAspNetCoreMvcModule) |
|||
)] |
|||
public class AbpOssManagementHttpApiModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly); |
|||
}); |
|||
|
|||
PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => |
|||
{ |
|||
options.AddAssemblyResource( |
|||
typeof(AbpOssManagementResource), |
|||
typeof(AbpOssManagementApplicationContractsModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
//public override void ConfigureServices(ServiceConfigurationContext context)
|
|||
//{
|
|||
// Configure<AbpLocalizationOptions>(options =>
|
|||
// {
|
|||
// options.Resources
|
|||
// .Get<AbpOssManagementResource>()
|
|||
// .AddBaseTypes(
|
|||
// typeof(AbpAuthorizationResource),
|
|||
// typeof(AbpValidationResource)
|
|||
// );
|
|||
// });
|
|||
//}
|
|||
} |
|||
} |
|||
|
|||
@ -1,9 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public interface IFileValidater |
|||
{ |
|||
Task ValidationAsync(UploadOssObjectInput input); |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.SettingManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpOssManagementApplicationContractsModule), |
|||
typeof(AbpAspNetCoreMvcModule))] |
|||
public class AbpOssManagementSettingManagementModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementSettingManagementModule).Assembly); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +1,51 @@ |
|||
# Oss-Management |
|||
|
|||
File-Management更名为Oss-Management |
|||
|
|||
## 模块说明 |
|||
|
|||
### 基础模块 |
|||
|
|||
* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 |
|||
* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口 |
|||
* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略 |
|||
* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口 |
|||
* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口 |
|||
* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合 |
|||
|
|||
### 高阶模块 |
|||
|
|||
* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理 |
|||
* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理 |
|||
* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理 |
|||
|
|||
### 权限定义 |
|||
|
|||
* AbpOssManagement.Container 授权对象是否允许访问容器(bucket) |
|||
* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket) |
|||
* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket) |
|||
* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象 |
|||
* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象 |
|||
* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象 |
|||
* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象 |
|||
|
|||
### 功能定义 |
|||
|
|||
* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件 |
|||
* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000 |
|||
* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12 |
|||
* AbpOssManagement.OssObject.UploadFile 用户可以上传文件 |
|||
* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000 |
|||
* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12 |
|||
* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现 |
|||
|
|||
### 配置定义 |
|||
|
|||
* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现 |
|||
* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100 |
|||
* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm |
|||
|
|||
## 更新日志 |
|||
|
|||
*【2021-03-10】 变更FileManagement命名空间为OssManagement |
|||
# Oss-Management |
|||
|
|||
File-Management更名为Oss-Management |
|||
|
|||
## 模块说明 |
|||
|
|||
### 基础模块 |
|||
|
|||
* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 |
|||
* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口 |
|||
* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略 |
|||
* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口 |
|||
* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口 |
|||
* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合 |
|||
|
|||
### 高阶模块 |
|||
|
|||
* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理 |
|||
* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理 |
|||
* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理 |
|||
|
|||
### 权限定义 |
|||
|
|||
* AbpOssManagement.Container 授权对象是否允许访问容器(bucket) |
|||
* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket) |
|||
* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket) |
|||
* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象 |
|||
* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象 |
|||
* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象 |
|||
* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象 |
|||
|
|||
### 功能定义 |
|||
|
|||
* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件 |
|||
* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000 |
|||
* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12 |
|||
* AbpOssManagement.OssObject.UploadFile 用户可以上传文件 |
|||
* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000 |
|||
* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12 |
|||
* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现 |
|||
|
|||
### 配置定义 |
|||
|
|||
* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现 |
|||
* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100 |
|||
* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm |
|||
|
|||
## 更新日志 |
|||
|
|||
*【2021-03-10】 变更FileManagement命名空间为OssManagement |
|||
*【2021-10-22】 增加PublicFilesController用于身份认证通过的用户上传/下载文件,所有操作限定在用户目录下 |
|||
|
|||
@ -1,21 +1,21 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:30030", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"LINGYUN.Abp.LocalizationManagement.HttpApi.Host": { |
|||
"commandName": "Project", |
|||
"dotnetRunMessages": "true", |
|||
"launchBrowser": false, |
|||
"applicationUrl": "http://0.0.0.0:30030", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:30030", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"LINGYUN.Abp.LocalizationManagement.HttpApi.Host": { |
|||
"commandName": "Project", |
|||
"dotnetRunMessages": "true", |
|||
"launchBrowser": false, |
|||
"applicationUrl": "http://0.0.0.0:30030", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,333 +1,342 @@ |
|||
using DotNetCore.CAP; |
|||
using LINGYUN.Abp.AspNetCore.HttpOverrides; |
|||
using LINGYUN.Abp.EventBus.CAP; |
|||
using LINGYUN.Abp.ExceptionHandling; |
|||
using LINGYUN.Abp.ExceptionHandling.Emailing; |
|||
using LINGYUN.Abp.Features.LimitValidation.Redis; |
|||
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; |
|||
using LINGYUN.Abp.MultiTenancy.DbFinder; |
|||
using LINGYUN.Abp.Notifications; |
|||
using LINGYUN.Abp.OssManagement; |
|||
using LINGYUN.Abp.OssManagement.FileSystem; |
|||
using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp; |
|||
using LINGYUN.Abp.OssManagement.SettingManagement; |
|||
using LINGYUN.Platform.EntityFrameworkCore; |
|||
using LINGYUN.Platform.HttpApi; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.DataProtection; |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.AspNetCore.Server.Kestrel.Core; |
|||
using Microsoft.Extensions.Caching.StackExchangeRedis; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.OpenApi.Models; |
|||
using StackExchange.Redis; |
|||
using System; |
|||
using System.IO; |
|||
using System.Text; |
|||
using System.Text.Encodings.Web; |
|||
using System.Text.Unicode; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Authentication.JwtBearer; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Security.Claims; |
|||
using Volo.Abp.Auditing; |
|||
using Volo.Abp.AuditLogging.EntityFrameworkCore; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.Caching.StackExchangeRedis; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.FeatureManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Http.Client.IdentityModel.Web; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.PermissionManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Security.Claims; |
|||
using Volo.Abp.Security.Encryption; |
|||
using Volo.Abp.SettingManagement.EntityFrameworkCore; |
|||
using Volo.Abp.TenantManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Threading; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Platform |
|||
{ |
|||
[DependsOn( |
|||
// typeof(AbpOssManagementAliyunModule),
|
|||
typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块
|
|||
typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块
|
|||
typeof(AbpOssManagementApplicationModule), |
|||
typeof(AbpOssManagementHttpApiModule), |
|||
typeof(AbpOssManagementSettingManagementModule), |
|||
typeof(PlatformApplicationModule), |
|||
typeof(PlatformHttpApiModule), |
|||
typeof(PlatformEntityFrameworkCoreModule), |
|||
typeof(AbpIdentityHttpApiClientModule), |
|||
typeof(AbpHttpClientIdentityModelWebModule), |
|||
typeof(AbpAspNetCoreMultiTenancyModule), |
|||
typeof(AbpFeatureManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAuditLoggingEntityFrameworkCoreModule), |
|||
typeof(AbpTenantManagementEntityFrameworkCoreModule), |
|||
typeof(AbpSettingManagementEntityFrameworkCoreModule), |
|||
typeof(AbpPermissionManagementEntityFrameworkCoreModule), |
|||
typeof(AbpLocalizationManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), |
|||
typeof(AbpNotificationModule), |
|||
typeof(AbpEmailingExceptionHandlingModule), |
|||
typeof(AbpCAPEventBusModule), |
|||
typeof(AbpFeaturesValidationRedisModule), |
|||
// typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块
|
|||
// typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块
|
|||
typeof(AbpDbFinderMultiTenancyModule), |
|||
typeof(AbpCachingStackExchangeRedisModule), |
|||
typeof(AbpAspNetCoreHttpOverridesModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public class AppPlatformHttpApiHostModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
PreConfigure<CapOptions>(options => |
|||
{ |
|||
options |
|||
.UseMySql(configuration.GetConnectionString("Default")) |
|||
.UseRabbitMQ(rabbitMQOptions => |
|||
{ |
|||
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); |
|||
}) |
|||
.UseDashboard(); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = hostingEnvironment.BuildConfiguration(); |
|||
|
|||
// 配置Ef
|
|||
Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.UseMySQL(); |
|||
}); |
|||
|
|||
//// 中文序列化的编码问题
|
|||
Configure<AbpSystemTextJsonSerializerOptions>(options => |
|||
{ |
|||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); |
|||
}); |
|||
|
|||
Configure<KestrelServerOptions>(options => |
|||
{ |
|||
options.Limits.MaxRequestBodySize = null; |
|||
options.Limits.MaxRequestBufferSize = null; |
|||
}); |
|||
|
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureAll((containerName, containerConfiguration) => |
|||
{ |
|||
containerConfiguration.UseFileSystem(fileSystem => |
|||
{ |
|||
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing"); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
// 加解密
|
|||
Configure<AbpStringEncryptionOptions>(options => |
|||
{ |
|||
var encryptionConfiguration = configuration.GetSection("Encryption"); |
|||
if (encryptionConfiguration.Exists()) |
|||
{ |
|||
options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase; |
|||
options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"]) |
|||
: options.DefaultSalt; |
|||
options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"]) |
|||
: options.InitVectorBytes; |
|||
} |
|||
}); |
|||
|
|||
// 自定义需要处理的异常
|
|||
Configure<AbpExceptionHandlingOptions>(options => |
|||
{ |
|||
// 加入需要处理的异常类型
|
|||
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>(); |
|||
options.Handlers.Add<AbpInitializationException>(); |
|||
options.Handlers.Add<ObjectDisposedException>(); |
|||
options.Handlers.Add<StackOverflowException>(); |
|||
options.Handlers.Add<OutOfMemoryException>(); |
|||
options.Handlers.Add<System.Data.Common.DbException>(); |
|||
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>(); |
|||
options.Handlers.Add<System.Data.DBConcurrencyException>(); |
|||
}); |
|||
// 自定义需要发送邮件通知的异常类型
|
|||
Configure<AbpEmailExceptionHandlingOptions>(options => |
|||
{ |
|||
// 是否发送堆栈信息
|
|||
options.SendStackTrace = true; |
|||
// 未指定异常接收者的默认接收邮件
|
|||
// 指定自己的邮件地址
|
|||
// options.DefaultReceiveEmail = "colin.in@foxmail.com";
|
|||
}); |
|||
|
|||
Configure<AbpDistributedCacheOptions>(options => |
|||
{ |
|||
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
|
|||
options.KeyPrefix = "LINGYUN.Abp.Application"; |
|||
// 滑动过期30天
|
|||
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); |
|||
// 绝对过期60天
|
|||
options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); |
|||
}); |
|||
|
|||
Configure<RedisCacheOptions>(options => |
|||
{ |
|||
var redisConfig = ConfigurationOptions.Parse(options.Configuration); |
|||
options.ConfigurationOptions = redisConfig; |
|||
options.InstanceName = configuration["Redis:InstanceName"]; |
|||
}); |
|||
|
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AppPlatformHttpApiHostModule>("LINGYUN.Platform"); |
|||
}); |
|||
|
|||
// 多租户
|
|||
Configure<AbpMultiTenancyOptions>(options => |
|||
{ |
|||
options.IsEnabled = true; |
|||
}); |
|||
|
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.ApplicationName = "Platform"; |
|||
// 是否启用实体变更记录
|
|||
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); |
|||
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>()) |
|||
{ |
|||
options |
|||
.EntityHistorySelectors |
|||
.AddAllEntities(); |
|||
} |
|||
}); |
|||
|
|||
// Swagger
|
|||
context.Services.AddSwaggerGen( |
|||
options => |
|||
{ |
|||
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" }); |
|||
options.DocInclusionPredicate((docName, description) => true); |
|||
options.CustomSchemaIds(type => type.FullName); |
|||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|||
{ |
|||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", |
|||
Name = "Authorization", |
|||
In = ParameterLocation.Header, |
|||
Scheme = "bearer", |
|||
Type = SecuritySchemeType.Http, |
|||
BearerFormat = "JWT" |
|||
}); |
|||
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|||
{ |
|||
{ |
|||
new OpenApiSecurityScheme |
|||
{ |
|||
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } |
|||
}, |
|||
new string[] { } |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
// 支持本地化语言类型
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
|||
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
|||
|
|||
options.Resources.AddDynamic(); |
|||
}); |
|||
|
|||
Configure<AbpClaimsMapOptions>(options => |
|||
{ |
|||
options.Maps.TryAdd("name", () => AbpClaimTypes.UserName); |
|||
}); |
|||
|
|||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|||
.AddJwtBearer(options => |
|||
{ |
|||
options.Authority = configuration["AuthServer:Authority"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.Audience = configuration["AuthServer:ApiName"]; |
|||
}); |
|||
|
|||
if (!hostingEnvironment.IsDevelopment()) |
|||
{ |
|||
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
|||
context.Services |
|||
.AddDataProtection() |
|||
.PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys"); |
|||
} |
|||
} |
|||
|
|||
//public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
|
|||
//{
|
|||
// var backgroundJobManager = context.ServiceProvider.GetRequiredService<IBackgroundJobManager>();
|
|||
// // 五分钟执行一次的定时任务
|
|||
// AsyncHelper.RunSync(async () => await
|
|||
// backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200)));
|
|||
//}
|
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
// http调用链
|
|||
app.UseCorrelationId(); |
|||
// 虚拟文件系统
|
|||
app.UseStaticFiles(); |
|||
// 本地化
|
|||
app.UseAbpRequestLocalization(); |
|||
// 多租户
|
|||
app.UseMultiTenancy(); |
|||
//路由
|
|||
app.UseRouting(); |
|||
// 认证
|
|||
app.UseAuthentication(); |
|||
// jwt
|
|||
app.UseJwtTokenMiddleware(); |
|||
// 授权
|
|||
app.UseAuthorization(); |
|||
// Swagger
|
|||
app.UseSwagger(); |
|||
// Swagger可视化界面
|
|||
app.UseSwaggerUI(options => |
|||
{ |
|||
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API"); |
|||
}); |
|||
// 审计日志
|
|||
app.UseAuditing(); |
|||
// 路由
|
|||
app.UseConfiguredEndpoints(); |
|||
|
|||
if (env.IsDevelopment()) |
|||
{ |
|||
AsyncHelper.RunSync(async () => |
|||
await app.ApplicationServices.GetRequiredService<IDataSeeder>() |
|||
.SeedAsync()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
using DotNetCore.CAP; |
|||
using LINGYUN.Abp.AspNetCore.HttpOverrides; |
|||
using LINGYUN.Abp.EventBus.CAP; |
|||
using LINGYUN.Abp.ExceptionHandling; |
|||
using LINGYUN.Abp.ExceptionHandling.Emailing; |
|||
using LINGYUN.Abp.Features.LimitValidation.Redis; |
|||
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; |
|||
using LINGYUN.Abp.MultiTenancy.DbFinder; |
|||
using LINGYUN.Abp.Notifications; |
|||
using LINGYUN.Abp.OssManagement; |
|||
using LINGYUN.Abp.OssManagement.FileSystem; |
|||
using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp; |
|||
using LINGYUN.Abp.OssManagement.SettingManagement; |
|||
using LINGYUN.Platform.EntityFrameworkCore; |
|||
using LINGYUN.Platform.HttpApi; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.DataProtection; |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.AspNetCore.Server.Kestrel.Core; |
|||
using Microsoft.Extensions.Caching.StackExchangeRedis; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.OpenApi.Models; |
|||
using StackExchange.Redis; |
|||
using System; |
|||
using System.IO; |
|||
using System.Text; |
|||
using System.Text.Encodings.Web; |
|||
using System.Text.Unicode; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Authentication.JwtBearer; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Security.Claims; |
|||
using Volo.Abp.Auditing; |
|||
using Volo.Abp.AuditLogging.EntityFrameworkCore; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.BlobStoring.FileSystem; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.Caching.StackExchangeRedis; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.FeatureManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Http.Client.IdentityModel.Web; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.PermissionManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Security.Claims; |
|||
using Volo.Abp.Security.Encryption; |
|||
using Volo.Abp.SettingManagement.EntityFrameworkCore; |
|||
using Volo.Abp.TenantManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Threading; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Platform |
|||
{ |
|||
[DependsOn( |
|||
// typeof(AbpOssManagementAliyunModule),
|
|||
typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块
|
|||
typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块
|
|||
typeof(AbpOssManagementApplicationModule), |
|||
typeof(AbpOssManagementHttpApiModule), |
|||
typeof(AbpOssManagementSettingManagementModule), |
|||
typeof(PlatformApplicationModule), |
|||
typeof(PlatformHttpApiModule), |
|||
typeof(PlatformEntityFrameworkCoreModule), |
|||
typeof(AbpIdentityHttpApiClientModule), |
|||
typeof(AbpHttpClientIdentityModelWebModule), |
|||
typeof(AbpAspNetCoreMultiTenancyModule), |
|||
typeof(AbpFeatureManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAuditLoggingEntityFrameworkCoreModule), |
|||
typeof(AbpTenantManagementEntityFrameworkCoreModule), |
|||
typeof(AbpSettingManagementEntityFrameworkCoreModule), |
|||
typeof(AbpPermissionManagementEntityFrameworkCoreModule), |
|||
typeof(AbpLocalizationManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), |
|||
typeof(AbpNotificationModule), |
|||
typeof(AbpEmailingExceptionHandlingModule), |
|||
typeof(AbpCAPEventBusModule), |
|||
typeof(AbpFeaturesValidationRedisModule), |
|||
// typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块
|
|||
// typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块
|
|||
typeof(AbpDbFinderMultiTenancyModule), |
|||
typeof(AbpCachingStackExchangeRedisModule), |
|||
typeof(AbpAspNetCoreHttpOverridesModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public class AppPlatformHttpApiHostModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
PreConfigure<CapOptions>(options => |
|||
{ |
|||
options |
|||
.UseMySql(configuration.GetConnectionString("Default")) |
|||
.UseRabbitMQ(rabbitMQOptions => |
|||
{ |
|||
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); |
|||
}) |
|||
.UseDashboard(); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = hostingEnvironment.BuildConfiguration(); |
|||
|
|||
// 配置Ef
|
|||
Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.UseMySQL(); |
|||
}); |
|||
|
|||
//// 中文序列化的编码问题
|
|||
Configure<AbpSystemTextJsonSerializerOptions>(options => |
|||
{ |
|||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); |
|||
}); |
|||
|
|||
Configure<KestrelServerOptions>(options => |
|||
{ |
|||
options.Limits.MaxRequestBodySize = null; |
|||
options.Limits.MaxRequestBufferSize = null; |
|||
}); |
|||
|
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureAll((containerName, containerConfiguration) => |
|||
{ |
|||
containerConfiguration.UseFileSystem(fileSystem => |
|||
{ |
|||
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing"); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
// 加解密
|
|||
Configure<AbpStringEncryptionOptions>(options => |
|||
{ |
|||
var encryptionConfiguration = configuration.GetSection("Encryption"); |
|||
if (encryptionConfiguration.Exists()) |
|||
{ |
|||
options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase; |
|||
options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"]) |
|||
: options.DefaultSalt; |
|||
options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"]) |
|||
: options.InitVectorBytes; |
|||
} |
|||
}); |
|||
|
|||
// 自定义需要处理的异常
|
|||
Configure<AbpExceptionHandlingOptions>(options => |
|||
{ |
|||
// 加入需要处理的异常类型
|
|||
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>(); |
|||
options.Handlers.Add<AbpInitializationException>(); |
|||
options.Handlers.Add<ObjectDisposedException>(); |
|||
options.Handlers.Add<StackOverflowException>(); |
|||
options.Handlers.Add<OutOfMemoryException>(); |
|||
options.Handlers.Add<System.Data.Common.DbException>(); |
|||
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>(); |
|||
options.Handlers.Add<System.Data.DBConcurrencyException>(); |
|||
}); |
|||
|
|||
Configure<Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingOptions>(options => |
|||
{ |
|||
// 是否发送错误详情
|
|||
options.SendExceptionsDetailsToClients = false; |
|||
}); |
|||
|
|||
// 自定义需要发送邮件通知的异常类型
|
|||
Configure<AbpEmailExceptionHandlingOptions>(options => |
|||
{ |
|||
// 是否发送堆栈信息
|
|||
options.SendStackTrace = true; |
|||
// 未指定异常接收者的默认接收邮件
|
|||
// 指定自己的邮件地址
|
|||
// options.DefaultReceiveEmail = "colin.in@foxmail.com";
|
|||
}); |
|||
|
|||
Configure<AbpDistributedCacheOptions>(options => |
|||
{ |
|||
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
|
|||
options.KeyPrefix = "LINGYUN.Abp.Application"; |
|||
// 滑动过期30天
|
|||
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); |
|||
// 绝对过期60天
|
|||
options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); |
|||
}); |
|||
|
|||
Configure<RedisCacheOptions>(options => |
|||
{ |
|||
var redisConfig = ConfigurationOptions.Parse(options.Configuration); |
|||
options.ConfigurationOptions = redisConfig; |
|||
options.InstanceName = configuration["Redis:InstanceName"]; |
|||
}); |
|||
|
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AppPlatformHttpApiHostModule>("LINGYUN.Platform"); |
|||
}); |
|||
|
|||
// 多租户
|
|||
Configure<AbpMultiTenancyOptions>(options => |
|||
{ |
|||
options.IsEnabled = true; |
|||
}); |
|||
|
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.ApplicationName = "Platform"; |
|||
// 是否启用实体变更记录
|
|||
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); |
|||
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>()) |
|||
{ |
|||
options |
|||
.EntityHistorySelectors |
|||
.AddAllEntities(); |
|||
} |
|||
}); |
|||
|
|||
// Swagger
|
|||
context.Services.AddSwaggerGen( |
|||
options => |
|||
{ |
|||
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" }); |
|||
options.DocInclusionPredicate((docName, description) => true); |
|||
options.CustomSchemaIds(type => type.FullName); |
|||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|||
{ |
|||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", |
|||
Name = "Authorization", |
|||
In = ParameterLocation.Header, |
|||
Scheme = "bearer", |
|||
Type = SecuritySchemeType.Http, |
|||
BearerFormat = "JWT" |
|||
}); |
|||
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|||
{ |
|||
{ |
|||
new OpenApiSecurityScheme |
|||
{ |
|||
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } |
|||
}, |
|||
new string[] { } |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
// 支持本地化语言类型
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
|||
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
|||
|
|||
options.Resources.AddDynamic(); |
|||
}); |
|||
|
|||
Configure<AbpClaimsMapOptions>(options => |
|||
{ |
|||
options.Maps.TryAdd("name", () => AbpClaimTypes.UserName); |
|||
}); |
|||
|
|||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|||
.AddJwtBearer(options => |
|||
{ |
|||
options.Authority = configuration["AuthServer:Authority"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.Audience = configuration["AuthServer:ApiName"]; |
|||
}); |
|||
|
|||
if (!hostingEnvironment.IsDevelopment()) |
|||
{ |
|||
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
|||
context.Services |
|||
.AddDataProtection() |
|||
.PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys"); |
|||
} |
|||
} |
|||
|
|||
//public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
|
|||
//{
|
|||
// var backgroundJobManager = context.ServiceProvider.GetRequiredService<IBackgroundJobManager>();
|
|||
// // 五分钟执行一次的定时任务
|
|||
// AsyncHelper.RunSync(async () => await
|
|||
// backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200)));
|
|||
//}
|
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
// http调用链
|
|||
app.UseCorrelationId(); |
|||
// 虚拟文件系统
|
|||
app.UseStaticFiles(); |
|||
// 本地化
|
|||
app.UseAbpRequestLocalization(); |
|||
// 多租户
|
|||
app.UseMultiTenancy(); |
|||
//路由
|
|||
app.UseRouting(); |
|||
// 认证
|
|||
app.UseAuthentication(); |
|||
// jwt
|
|||
app.UseJwtTokenMiddleware(); |
|||
// 授权
|
|||
app.UseAuthorization(); |
|||
// Swagger
|
|||
app.UseSwagger(); |
|||
// Swagger可视化界面
|
|||
app.UseSwaggerUI(options => |
|||
{ |
|||
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API"); |
|||
}); |
|||
// 审计日志
|
|||
app.UseAuditing(); |
|||
// 工作单元
|
|||
app.UseUnitOfWork(); |
|||
// 路由
|
|||
app.UseConfiguredEndpoints(); |
|||
|
|||
if (env.IsDevelopment()) |
|||
{ |
|||
AsyncHelper.RunSync(async () => |
|||
await app.ApplicationServices.GetRequiredService<IDataSeeder>() |
|||
.SeedAsync()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue