Browse Source

feat(localization): dynamically localized resources are initialized at startup time

pull/327/head
cKey 4 years ago
parent
commit
ce758de4a3
  1. 7
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs
  2. 22
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs
  3. 45
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs
  4. 91
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs
  5. 14
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/ILocalizationDispatcher.cs
  6. 17
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/ILocalizationSubscriber.cs
  7. 10
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationDictionary.cs
  8. 61
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs
  9. 33
      aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationSubscriber.cs
  10. 96
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileValidater.cs
  11. 89
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs
  12. 75
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs
  13. 41
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs

7
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.EventBus;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EventBus;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
@ -9,5 +10,9 @@ namespace LINGYUN.Abp.Localization.Dynamic
typeof(AbpLocalizationModule))]
public class AbpLocalizationDynamicModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHostedService<DynamicLocalizationInitializeService>();
}
}
}

22
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs

@ -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);
}
}
}

45
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs

@ -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;
}
}
}

91
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs

@ -1,27 +1,16 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Nito.AsyncEx;
using System;
using Microsoft.Extensions.Options;
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();
private AbpLocalizationDynamicOptions _options;
public DynamicLocalizationResourceContributor(string resourceName)
{
@ -30,11 +19,7 @@ namespace LINGYUN.Abp.Localization.Dynamic
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);
_options = context.ServiceProvider.GetService<IOptions<AbpLocalizationDynamicOptions>>().Value;
}
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary)
@ -49,72 +34,8 @@ namespace LINGYUN.Abp.Localization.Dynamic
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;
return _options.LocalizationDictionary
.GetOrAdd(_resourceName, () => new Dictionary<string, ILocalizationDictionary>());
}
}
}

14
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/ILocalizationDispatcher.cs

@ -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);
}
}

17
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/ILocalizationSubscriber.cs

@ -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);
}
}

10
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationDictionary.cs

@ -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>>
{
}
}

61
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs

@ -1,6 +1,11 @@
using System.Threading.Tasks;
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
{
@ -8,16 +13,60 @@ namespace LINGYUN.Abp.Localization.Dynamic
IDistributedEventHandler<LocalizedStringCacheResetEventData>,
ITransientDependency
{
private readonly ILocalizationDispatcher _dispatcher;
private readonly AbpLocalizationDynamicOptions _options;
public LocalizationResetSynchronizer(
ILocalizationDispatcher dispatcher)
IOptions<AbpLocalizationDynamicOptions> options)
{
_dispatcher = dispatcher;
_options = options.Value;
}
public async Task HandleEventAsync(LocalizedStringCacheResetEventData eventData)
public virtual Task HandleEventAsync(LocalizedStringCacheResetEventData eventData)
{
await _dispatcher.DispatchAsync(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>());
}
}
}

33
aspnet-core/modules/common/LINGYUN.Abp.Localization.Dynamic/LINGYUN/Abp/Localization/Dynamic/LocalizationSubscriber.cs

@ -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);
}
}
}

96
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileValidater.cs

@ -0,0 +1,96 @@
using LINGYUN.Abp.OssManagement.Localization;
using LINGYUN.Abp.OssManagement.Settings;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Localization;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IO;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.OssManagement
{
public class FileValidater : IFileValidater, ISingletonDependency
{
private readonly IMemoryCache _cache;
private readonly ISettingProvider _settingProvider;
private readonly IServiceProvider _serviceProvider;
private readonly IStringLocalizer _stringLocalizer;
public FileValidater(
IMemoryCache cache,
ISettingProvider settingProvider,
IServiceProvider serviceProvider,
IStringLocalizer<AbpOssManagementResource> stringLocalizer)
{
_cache = cache;
_settingProvider = settingProvider;
_serviceProvider = serviceProvider;
_stringLocalizer = stringLocalizer;
}
public virtual async Task ValidationAsync(UploadFile input)
{
var validation = await GetByCacheItemAsync();
if (validation.SizeLimit * 1024 * 1024 < input.TotalSize)
{
throw new UserFriendlyException(_stringLocalizer["UploadFileSizeBeyondLimit", validation.SizeLimit]);
}
var fileExtensionName = FileHelper.GetExtension(input.FileName);
if (!validation.AllowedExtensions
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase)))
{
throw new UserFriendlyException(_stringLocalizer["NotAllowedFileExtensionName", fileExtensionName]);
}
}
protected virtual async Task<FileValidation> GetByCacheItemAsync()
{
var fileValidation = _cache.Get<FileValidation>(FileValidation.CacheKey);
if (fileValidation == null)
{
fileValidation = await GetBySettingAsync();
_cache.Set(FileValidation.CacheKey,
fileValidation,
new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(2)
});
}
return fileValidation;
}
protected virtual async Task<FileValidation> GetBySettingAsync()
{
var fileSizeLimited = await _settingProvider
.GetAsync(
AbpOssManagementSettingNames.FileLimitLength,
AbpOssManagementSettingNames.DefaultFileLimitLength);
var fileAllowExtension = await _settingProvider
.GetOrDefaultAsync(AbpOssManagementSettingNames.AllowFileExtensions, _serviceProvider);
return new FileValidation(fileSizeLimited, fileAllowExtension.Split(','));
}
}
public class FileValidation
{
public const string CacheKey = "Abp.OssManagement.FileValidation";
public long SizeLimit { get; set; }
public string[] AllowedExtensions { get; set; }
public FileValidation()
{
}
public FileValidation(
long sizeLimit,
string[] allowedExtensions)
{
SizeLimit = sizeLimit;
AllowedExtensions = allowedExtensions;
}
}
}

89
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs

@ -0,0 +1,89 @@
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features;
using Microsoft.AspNetCore.Authorization;
using System.IO;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.Features;
using Volo.Abp.Users;
namespace LINGYUN.Abp.OssManagement
{
/// <summary>
/// 所有登录用户公开访问文件服务接口
/// bucket限制在users
/// path限制在用户id
/// </summary>
[Authorize]
// 不对外公开,仅通过控制器调用
[RemoteService(IsEnabled = false, IsMetadataEnabled = false)]
public class PublicFileAppService : OssManagementApplicationServiceBase, IPublicFileAppService
{
private readonly IFileValidater _fileValidater;
private readonly IOssContainerFactory _ossContainerFactory;
public PublicFileAppService(
IFileValidater fileValidater,
IOssContainerFactory ossContainerFactory)
{
_fileValidater = fileValidater;
_ossContainerFactory = ossContainerFactory;
}
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.UploadLimit,
AbpOssManagementFeatureNames.OssObject.UploadInterval,
LimitPolicy.Month)]
public virtual async Task<OssObjectDto> UploadAsync(UploadPublicFileInput input)
{
await _fileValidater.ValidationAsync(new UploadFile
{
TotalSize = input.Content.Length,
FileName = input.Object
});
var oss = _ossContainerFactory.Create();
var createOssObjectRequest = new CreateOssObjectRequest(
"users",
HttpUtility.UrlDecode(input.Object),
input.Content,
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)))
{
Overwrite = input.Overwrite
};
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.DownloadLimit,
AbpOssManagementFeatureNames.OssObject.DownloadInterval,
LimitPolicy.Month)]
public virtual async Task<Stream> GetAsync(GetPublicFileInput input)
{
var ossObjectRequest = new GetOssObjectRequest(
"users", // 需要处理特殊字符
HttpUtility.UrlDecode(input.Name),
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)),
HttpUtility.UrlDecode(input.Process));
var ossContainer = _ossContainerFactory.Create();
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest);
return ossObject.Content;
}
private string GetCurrentUserPath(string path)
{
path = path.StartsWith("/") ? path.Substring(1) : path;
var userId = CurrentUser.GetId().ToString();
return path.StartsWith(userId) ? path : $"{userId}/{path}";
}
}
}

75
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs

@ -0,0 +1,75 @@
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Validation.StringValues;
namespace LINGYUN.Abp.OssManagement.Features
{
public class AbpOssManagementFeatureDefinitionProvider : FeatureDefinitionProvider
{
public override void Define(IFeatureDefinitionContext context)
{
var featureGroup = context.AddGroup(
name: AbpOssManagementFeatureNames.GroupName,
displayName: L("Features:OssManagement"));
var ossFeature = featureGroup.AddFeature(
name: AbpOssManagementFeatureNames.OssObject.Default,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:OssObject"),
description: L("Features:Description:OssObject"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadFile,
defaultValue: false.ToString(),
displayName: L("Features:DisplayName:DownloadFile"),
description: L("Features:Description:DownloadFile"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadLimit,
defaultValue: "1000",
displayName: L("Features:DisplayName:DownloadLimit"),
description: L("Features:Description:DownloadLimit"),
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadInterval,
defaultValue: "1",
displayName: L("Features:DisplayName:DownloadInterval"),
description: L("Features:Description:DownloadInterval"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadFile,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:UploadFile"),
description: L("Features:Description:UploadFile"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadLimit,
defaultValue: "1000",
displayName: L("Features:DisplayName:UploadLimit"),
description: L("Features:Description:UploadLimit"),
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadInterval,
defaultValue: "1",
displayName: L("Features:DisplayName:UploadInterval"),
description: L("Features:Description:UploadInterval"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
// TODO: 此功能需要控制器协同,暂时不实现
//fileSystemFeature.CreateChild(
// name: AbpOssManagementFeatureNames.OssObject.MaxUploadFileCount,
// defaultValue: 1.ToString(),
// displayName: L("Features:DisplayName:MaxUploadFileCount"),
// description: L("Features:Description:MaxUploadFileCount"),
// valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10)));
}
protected ILocalizableString L(string name)
{
return LocalizableString.Create<AbpOssManagementResource>(name);
}
}
}

41
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs

@ -0,0 +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";
}
}
}
Loading…
Cancel
Save