63 changed files with 655 additions and 469 deletions
@ -1,20 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
<RootNamespace /><GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
|
||||
<Version>3.0.0</Version> |
|
||||
<Authors>LINGYUN</Authors> |
|
||||
<Description>七牛云Oss对象存储Abp集成</Description> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|
||||
<OutputPath>D:\LocalNuget</OutputPath> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Qiniu.Shared" Version="7.2.15" /> |
|
||||
<PackageReference Include="Volo.Abp.BlobStoring" Version="3.0.0" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System; |
|
||||
using Volo.Abp.BlobStoring; |
|
||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
[DependsOn(typeof(AbpBlobStoringModule))] |
|
||||
public class AbpBlobStoringQiniuModule : AbpModule |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,24 +0,0 @@ |
|||||
using Volo.Abp.BlobStoring; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public class DefaultQiniuBlobNameCalculator : IQiniuBlobNameCalculator, ITransientDependency |
|
||||
{ |
|
||||
protected ICurrentTenant CurrentTenant { get; } |
|
||||
|
|
||||
public DefaultQiniuBlobNameCalculator( |
|
||||
ICurrentTenant currentTenant) |
|
||||
{ |
|
||||
CurrentTenant = currentTenant; |
|
||||
} |
|
||||
|
|
||||
public string Calculate(BlobProviderArgs args) |
|
||||
{ |
|
||||
return CurrentTenant.Id == null |
|
||||
? $"host/{args.BlobName}" |
|
||||
: $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
using Volo.Abp.BlobStoring; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public interface IQiniuBlobNameCalculator |
|
||||
{ |
|
||||
string Calculate(BlobProviderArgs args); |
|
||||
} |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
using System; |
|
||||
using Volo.Abp.BlobStoring; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public static class QiniuBlobContainerConfigurationExtensions |
|
||||
{ |
|
||||
public static QiniuBlobProviderConfiguration GetQiniuConfiguration( |
|
||||
this BlobContainerConfiguration containerConfiguration) |
|
||||
{ |
|
||||
return new QiniuBlobProviderConfiguration(containerConfiguration); |
|
||||
} |
|
||||
|
|
||||
public static BlobContainerConfiguration UseQiniu( |
|
||||
this BlobContainerConfiguration containerConfiguration, |
|
||||
Action<QiniuBlobProviderConfiguration> qiniuConfigureAction) |
|
||||
{ |
|
||||
containerConfiguration.ProviderType = typeof(QiniuBlobProvider); |
|
||||
|
|
||||
qiniuConfigureAction(new QiniuBlobProviderConfiguration(containerConfiguration)); |
|
||||
|
|
||||
return containerConfiguration; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,50 +0,0 @@ |
|||||
using Qiniu.Util; |
|
||||
using System; |
|
||||
using System.IO; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.BlobStoring; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using QiniuConfig = Qiniu.Common.Config; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public class QiniuBlobProvider : BlobProviderBase, ITransientDependency |
|
||||
{ |
|
||||
protected IQiniuBlobNameCalculator QiniuBlobNameCalculator { get; } |
|
||||
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public override Task SaveAsync(BlobProviderSaveArgs args) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
private Mac GetMac(BlobProviderArgs args) |
|
||||
{ |
|
||||
var configuration = args.Configuration.GetQiniuConfiguration(); |
|
||||
return new Mac(configuration.AccessKey, configuration.SecretKey); |
|
||||
} |
|
||||
|
|
||||
private string GetAndInitBucketName(BlobProviderArgs args) |
|
||||
{ |
|
||||
var configuration = args.Configuration.GetQiniuConfiguration(); |
|
||||
var bucketName = configuration.BucketName.IsNullOrWhiteSpace() |
|
||||
? args.ContainerName |
|
||||
: configuration.BucketName; |
|
||||
QiniuConfig.AutoZone(configuration.AccessKey, bucketName, true); |
|
||||
return bucketName; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,85 +0,0 @@ |
|||||
using Volo.Abp; |
|
||||
using Volo.Abp.BlobStoring; |
|
||||
|
|
||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public class QiniuBlobProviderConfiguration |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Api授权码
|
|
||||
/// </remarks>
|
|
||||
public string AccessKey |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfiguration<string>(QiniuBlobProviderConfigurationNames.AccessKey); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.AccessKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// Api密钥
|
|
||||
/// </summary>
|
|
||||
public string SecretKey |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfiguration<string>(QiniuBlobProviderConfigurationNames.SecretKey); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.SecretKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 默认的Bucket名称
|
|
||||
/// </summary>
|
|
||||
public string BucketName |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.BucketName, ""); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.BucketName, value ?? ""); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 默认自动删除该文件天数
|
|
||||
/// 默认 0,不删除
|
|
||||
/// </summary>
|
|
||||
public int DeleteAfterDays |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.DeleteAfterDays, 0); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.DeleteAfterDays, value); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL。
|
|
||||
/// 必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL
|
|
||||
/// </summary>
|
|
||||
public string UploadCallbackUrl |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackUrl, ""); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackUrl, value ?? ""); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送回调通知时的 Host 值。
|
|
||||
/// 与 callbackUrl 配合使用,仅当设置了 callbackUrl 时才有效。
|
|
||||
/// </summary>
|
|
||||
public string UploadCallbackHost |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackHost, ""); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackHost, value ?? ""); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。
|
|
||||
/// 默认为 application/x-www-form-urlencoded,也可设置为 application/json。
|
|
||||
/// </summary>
|
|
||||
public string UploadCallbackBodyType |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackBodyType, ""); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackBodyType, value ?? ""); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,自定义七牛云最终返回給上传端(在指定 returnUrl 时是携带在跳转路径参数中)的数据。
|
|
||||
/// 支持魔法变量和自定义变量。returnBody 要求是合法的 JSON 文本。
|
|
||||
/// 例如 {"key": $(key), "hash": $(etag), "w": $(imageInfo.width), "h": $(imageInfo.height)}。
|
|
||||
/// </summary>
|
|
||||
public string UploadCallbackBody |
|
||||
{ |
|
||||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackBody, ""); |
|
||||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackBody, value ?? ""); |
|
||||
} |
|
||||
private readonly BlobContainerConfiguration _containerConfiguration; |
|
||||
|
|
||||
public QiniuBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) |
|
||||
{ |
|
||||
_containerConfiguration = containerConfiguration; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|
||||
{ |
|
||||
public static class QiniuBlobProviderConfigurationNames |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Api授权码
|
|
||||
/// </summary>
|
|
||||
public const string AccessKey = "Qiniu:OSS:AccessKey"; |
|
||||
/// <summary>
|
|
||||
/// Api密钥
|
|
||||
/// </summary>
|
|
||||
public const string SecretKey = "Qiniu:OSS:SecretKey"; |
|
||||
/// <summary>
|
|
||||
/// 默认的Bucket名称
|
|
||||
/// </summary>
|
|
||||
public const string BucketName = "Qiniu:OSS:BucketName"; |
|
||||
/// <summary>
|
|
||||
/// 默认自动删除该文件天数
|
|
||||
/// 默认 0,不删除
|
|
||||
/// </summary>
|
|
||||
public const string DeleteAfterDays = "Qiniu:OSS:DeleteAfterDays"; |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL。
|
|
||||
/// 必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL
|
|
||||
/// </summary>
|
|
||||
public const string UploadCallbackUrl = "Qiniu:OSS:UploadCallbackUrl"; |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送回调通知时的 Host 值。
|
|
||||
/// 与 callbackUrl 配合使用,仅当设置了 callbackUrl 时才有效。
|
|
||||
/// </summary>
|
|
||||
public const string UploadCallbackHost = "Qiniu:OSS:UploadCallbackHost"; |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。
|
|
||||
/// 默认为 application/x-www-form-urlencoded,也可设置为 application/json。
|
|
||||
/// </summary>
|
|
||||
public const string UploadCallbackBodyType = "Qiniu:OSS:UploadCallbackBodyType"; |
|
||||
/// <summary>
|
|
||||
/// 上传成功后,自定义七牛云最终返回給上传端(在指定 returnUrl 时是携带在跳转路径参数中)的数据。
|
|
||||
/// 支持魔法变量和自定义变量。returnBody 要求是合法的 JSON 文本。
|
|
||||
/// 例如 {"key": $(key), "hash": $(etag), "w": $(imageInfo.width), "h": $(imageInfo.height)}。
|
|
||||
/// </summary>
|
|
||||
public const string UploadCallbackBody = "Qiniu:OSS:UploadCallbackBody"; |
|
||||
} |
|
||||
} |
|
||||
@ -1,18 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
<RootNamespace /> |
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
|
||||
<Version>3.0.0</Version> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|
||||
<OutputPath>D:\LocalNuget</OutputPath> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Volo.Abp.Identity.Domain" Version="3.0.0" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,77 +0,0 @@ |
|||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.Identity.Settings; |
|
||||
using Volo.Abp.Options; |
|
||||
using Volo.Abp.Settings; |
|
||||
using Volo.Abp.Threading; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Identity |
|
||||
{ |
|
||||
public class AbpIdentityOverrideOptionsFactory : AbpOptionsFactory<IdentityOptions> |
|
||||
{ |
|
||||
protected ISettingStore SettingStore { get; } |
|
||||
public AbpIdentityOverrideOptionsFactory( |
|
||||
ISettingStore settingStore, |
|
||||
IEnumerable<IConfigureOptions<IdentityOptions>> setups, |
|
||||
IEnumerable<IPostConfigureOptions<IdentityOptions>> postConfigures) |
|
||||
: base(setups, postConfigures) |
|
||||
{ |
|
||||
SettingStore = settingStore; |
|
||||
} |
|
||||
|
|
||||
public override IdentityOptions Create(string name) |
|
||||
{ |
|
||||
var options = base.Create(name); |
|
||||
|
|
||||
// 重写为只获取公共配置
|
|
||||
OverrideOptions(options); |
|
||||
|
|
||||
return options; |
|
||||
} |
|
||||
|
|
||||
protected virtual void OverrideOptions(IdentityOptions options) |
|
||||
{ |
|
||||
AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task OverrideOptionsAsync(IdentityOptions options) |
|
||||
{ |
|
||||
options.Password.RequiredLength = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength); |
|
||||
options.Password.RequiredUniqueChars = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars); |
|
||||
options.Password.RequireNonAlphanumeric = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric); |
|
||||
options.Password.RequireLowercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase); |
|
||||
options.Password.RequireUppercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase); |
|
||||
options.Password.RequireDigit = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit); |
|
||||
|
|
||||
options.Lockout.AllowedForNewUsers = await GetOrDefaultAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers); |
|
||||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await GetOrDefaultAsync(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To<int>())); |
|
||||
options.Lockout.MaxFailedAccessAttempts = await GetOrDefaultAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts); |
|
||||
|
|
||||
options.SignIn.RequireConfirmedEmail = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail); |
|
||||
options.SignIn.RequireConfirmedPhoneNumber = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task<T> GetOrDefaultAsync<T>(string name, T defaultValue = default(T)) where T : struct |
|
||||
{ |
|
||||
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null); |
|
||||
if (setting.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
return defaultValue; |
|
||||
} |
|
||||
return setting.To<T>(); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task<string> GetOrDefaultAsync(string name, string defaultValue = "") |
|
||||
{ |
|
||||
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null); |
|
||||
if (setting.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
return defaultValue; |
|
||||
} |
|
||||
return setting; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,37 +0,0 @@ |
|||||
using Microsoft.AspNetCore.Identity; |
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using System; |
|
||||
using Volo.Abp.Identity; |
|
||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Identity |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 重写IdentityOptions,主要替换配置工厂组件,不再从SettingProvider获取IdentityOptions配置
|
|
||||
/// 在跨服务器时,从SettingProvider获取配置,用户需等待很长的时间,严重影响体验
|
|
||||
/// 如果是本地服务器,可以忽略这些性能影响,不需要引用此模块
|
|
||||
/// </summary>
|
|
||||
[DependsOn(typeof(AbpIdentityDomainModule))] |
|
||||
public class AbpIdentityOverrideOptionsModule : AbpModule |
|
||||
{ |
|
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
|
||||
{ |
|
||||
// TODO:配置文件指定IdentityOptions,避免从数据库读取的超长时间等待
|
|
||||
// 问题点:https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs
|
|
||||
// 有11个同步等待任务去获取身份认证配置,如果缓存不存在,会执行11条数据库指令
|
|
||||
// 运行过程中严重影响体验
|
|
||||
context.Services.Replace(ServiceDescriptor.Transient<IOptionsFactory<IdentityOptions>, AbpIdentityOverrideOptionsFactory>()); |
|
||||
context.Services.Replace(ServiceDescriptor.Transient<IOptions<IdentityOptions>, OptionsManager<IdentityOptions>>()); |
|
||||
|
|
||||
var configuration = context.Services.GetConfiguration(); |
|
||||
Configure<IdentityOptions>(configuration.GetSection("Identity")); |
|
||||
Configure<IdentityOptions>(options => |
|
||||
{ |
|
||||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(configuration.GetSection("Identity:Lockout:LockoutDuration").Get<int>()); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,27 @@ |
|||||
|
using LINGYUN.Platform.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
[DependsOn(typeof(AppPlatformDomainSharedModule))] |
||||
|
public class AppPlatformApplicationContractModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AppPlatformApplicationContractModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Get<PlatformResource>() |
||||
|
.AddVirtualJson("/LINGYUN/Platform/Localization/ApplicationContracts"); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Permission:Platform": "Platform service", |
||||
|
"Permission:AppVersion": "Version management", |
||||
|
"Permission:FileSystem": "File system", |
||||
|
"Permission:FileManager": "File management", |
||||
|
"Permission:CreateVersion": "Create version", |
||||
|
"Permission:DeleteVersion": "Delete version", |
||||
|
"Permission:CreateFolder": "Create directory", |
||||
|
"Permission:DeleteFolder": "Delete directory", |
||||
|
"Permission:RenameFolder": "Directory rename", |
||||
|
"Permission:MoveFolder": "Change directory", |
||||
|
"Permission:CopyFolder": "Copy directory", |
||||
|
"Permission:AppendFile": "Add files", |
||||
|
"Permission:UpdateFile": "Change file", |
||||
|
"Permission:DeleteFile": "Delete file", |
||||
|
"Permission:CopyFile": "Copy file", |
||||
|
"Permission:MoveFile": "Move file", |
||||
|
"Permission:DownloadFile": "Download file" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Permission:Platform": "平台服务", |
||||
|
"Permission:AppVersion": "版本管理", |
||||
|
"Permission:FileSystem": "文件系统", |
||||
|
"Permission:FileManager": "文件管理", |
||||
|
"Permission:CreateVersion": "创建版本", |
||||
|
"Permission:DeleteVersion": "删除版本", |
||||
|
"Permission:CreateFolder": "创建目录", |
||||
|
"Permission:DeleteFolder": "删除目录", |
||||
|
"Permission:RenameFolder": "目录改名", |
||||
|
"Permission:MoveFolder": "变更目录", |
||||
|
"Permission:CopyFolder": "复制目录", |
||||
|
"Permission:AppendFile": "添加文件", |
||||
|
"Permission:UpdateFile": "变更文件", |
||||
|
"Permission:DeleteFile": "删除文件", |
||||
|
"Permission:CopyFile": "复制文件", |
||||
|
"Permission:MoveFile": "移动文件", |
||||
|
"Permission:DownloadFile": "下载文件" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using LINGYUN.Platform.Localization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Permissions |
||||
|
{ |
||||
|
public class PlatformPermissionDefinitionProvider : PermissionDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IPermissionDefinitionContext context) |
||||
|
{ |
||||
|
var platform = context.AddGroup(PlatformPermissions.GroupName, L("Permission:Platform")); |
||||
|
|
||||
|
var appVersion = platform.AddPermission(PlatformPermissions.AppVersion.Default, L("Permission:AppVersion")); |
||||
|
appVersion.AddChild(PlatformPermissions.AppVersion.Create, L("Permission:CreateVersion")); |
||||
|
appVersion.AddChild(PlatformPermissions.AppVersion.Delete, L("Permission:DeleteVersion")); |
||||
|
|
||||
|
var versionFile = appVersion.AddChild(PlatformPermissions.AppVersion.FileManager.Default, L("Permission:FileManager")); |
||||
|
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Create, L("Permission:AppendFile")); |
||||
|
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Delete, L("Permission:DeleteFile")); |
||||
|
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Download, L("Permission:DownloadFile")); |
||||
|
|
||||
|
// TODO: 2020-07-27 目前abp不支持对象存储管理(或者属于企业版?)需要创建一个 LINGYUN.Abp.BlobStoring 项目自行实现
|
||||
|
|
||||
|
var fileSystem = platform.AddPermission(PlatformPermissions.FileSystem.Default, L("Permission:FileSystem")); |
||||
|
fileSystem.AddChild(PlatformPermissions.FileSystem.Create, L("Permission:CreateFolder")); |
||||
|
fileSystem.AddChild(PlatformPermissions.FileSystem.Delete, L("Permission:DeleteFolder")); |
||||
|
fileSystem.AddChild(PlatformPermissions.FileSystem.Rename, L("Permission:RenameFolder")); |
||||
|
fileSystem.AddChild(PlatformPermissions.FileSystem.Copy, L("Permission:CopyFolder")); |
||||
|
fileSystem.AddChild(PlatformPermissions.FileSystem.Move, L("Permission:MoveFolder")); |
||||
|
|
||||
|
var fileManager = fileSystem.AddChild(PlatformPermissions.FileSystem.FileManager.Default, L("Permission:FileManager")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Create, L("Permission:AppendFile")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Update, L("Permission:UpdateFile")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Delete, L("Permission:DeleteFile")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Copy, L("Permission:CopyFile")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Move, L("Permission:MoveFile")); |
||||
|
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Download, L("Permission:DownloadFile")); |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<PlatformResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Permissions |
||||
|
{ |
||||
|
public class PlatformPermissions |
||||
|
{ |
||||
|
public const string GroupName = "Platform"; |
||||
|
|
||||
|
// 如果abp后期提供对象存储的目录管理接口,则启用此权限
|
||||
|
/// <summary>
|
||||
|
/// 文件系统
|
||||
|
/// </summary>
|
||||
|
public class FileSystem |
||||
|
{ |
||||
|
public const string Default = GroupName + ".FileSystem"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Rename = Default + ".Rename"; |
||||
|
|
||||
|
public const string Copy = Default + ".Copy"; |
||||
|
|
||||
|
public const string Move = Default + ".Move"; |
||||
|
|
||||
|
public class FileManager |
||||
|
{ |
||||
|
public const string Default = FileSystem.Default + ".FileManager"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Copy = Default + ".Copy"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Update = Default + ".Update"; |
||||
|
|
||||
|
public const string Move = Default + ".Move"; |
||||
|
|
||||
|
public const string Download = Default + ".Download"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class AppVersion |
||||
|
{ |
||||
|
public const string Default = GroupName + ".AppVersion"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public class FileManager |
||||
|
{ |
||||
|
public const string Default = AppVersion.Default + ".FileManager"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Download = Default + ".Download"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static string[] GetAll() |
||||
|
{ |
||||
|
return ReflectionHelper.GetPublicConstantsRecursively(typeof(PlatformPermissions)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,10 +0,0 @@ |
|||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace LINGYUN.Platform |
|
||||
{ |
|
||||
[DependsOn(typeof(PlatformDomainSharedModule))] |
|
||||
public class PlatformApplicationContractModule : AbpModule |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,16 @@ |
|||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public static class BlobConsts |
||||
|
{ |
||||
|
public static int MaxNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 255; |
||||
|
public static int MaxSha256Length |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 65; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public static class BlobContainerConsts |
||||
|
{ |
||||
|
public static int MaxNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 255; |
||||
|
|
||||
|
public static int MaxPathLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 255; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public static class PlatformErrorCodes |
||||
|
{ |
||||
|
public const string VersionFileNotFound = "Platform.VersionFile:404"; |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,6 @@ |
|||||
namespace LINGYUN.Platform |
namespace LINGYUN.Platform |
||||
{ |
{ |
||||
public static class PlatformDbProperties |
public static class AppPlatformDbProperties |
||||
{ |
{ |
||||
public static string DbTablePrefix { get; set; } = "AppPlatform"; |
public static string DbTablePrefix { get; set; } = "AppPlatform"; |
||||
|
|
||||
@ -0,0 +1,35 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public class Blob : AuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid ContainerId { get; protected set; } |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
public virtual string Name { get; protected set; } |
||||
|
public virtual string Sha256 { get; protected set; } |
||||
|
public virtual long Size { get; protected set; } |
||||
|
protected Blob() { } |
||||
|
public Blob(Guid id, Guid containerId, [NotNull] string name, [NotNull] string sha256, long size, Guid? tenantId) |
||||
|
{ |
||||
|
Id = id; |
||||
|
ContainerId = containerId; |
||||
|
ChangeFile(name, sha256, size); |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
public void ChangeFile(string name, string sha256, long size) |
||||
|
{ |
||||
|
Name = Check.NotNullOrWhiteSpace(name, nameof(name), BlobConsts.MaxNameLength); |
||||
|
Sha256 = Check.NotNullOrWhiteSpace(sha256, nameof(sha256), BlobConsts.MaxSha256Length); |
||||
|
Size = size; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public class BlobContainer : AuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
public virtual string Name { get; protected set; } |
||||
|
public BlobContainer(Guid id, [NotNull] string name, Guid? tenantId = null) |
||||
|
: base(id) |
||||
|
{ |
||||
|
Name = Check.NotNullOrWhiteSpace(name, nameof(name), BlobContainerConsts.MaxNameLength); |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.Domain.Services; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public class BlobStoringManager : DomainService |
||||
|
{ |
||||
|
private IBlobRepository _blobRepository; |
||||
|
protected IBlobRepository BlobRepository => LazyGetRequiredService(ref _blobRepository); |
||||
|
|
||||
|
private IBlobContainerRepository _containerRepository; |
||||
|
protected IBlobContainerRepository ContainerRepository => LazyGetRequiredService(ref _containerRepository); |
||||
|
|
||||
|
protected IBlobContainerFactory BlobContainerFactory { get; } |
||||
|
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } |
||||
|
|
||||
|
public virtual async Task CreateContainerAsync(string name) |
||||
|
{ |
||||
|
var containerConfiguration = BlobContainerConfigurationProvider.Get<OSSContainer>(); |
||||
|
var containerName = NormalizeContainerName(containerConfiguration, name); |
||||
|
if (await ContainerRepository.ContainerExistsAsync(name)) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
// 框架暂时未实现创建Container ,这里采用保存一个空文件,然后删除此文件的方法来创建Container
|
||||
|
var blobContainer = BlobContainerFactory.Create(containerName); |
||||
|
try |
||||
|
{ |
||||
|
var emptyBlobData = System.Text.Encoding.UTF8.GetBytes(""); |
||||
|
await blobContainer.SaveAsync("empty.txt", emptyBlobData, true); |
||||
|
var container = new BlobContainer(GuidGenerator.Create(), containerName, CurrentTenant.Id) |
||||
|
{ |
||||
|
CreationTime = Clock.Now |
||||
|
}; |
||||
|
await ContainerRepository.InsertAsync(container); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
await blobContainer.DeleteAsync("empty.txt"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual string NormalizeContainerName(BlobContainerConfiguration configuration, string containerName) |
||||
|
{ |
||||
|
if (!configuration.NamingNormalizers.Any()) |
||||
|
{ |
||||
|
return containerName; |
||||
|
} |
||||
|
|
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
foreach (var normalizerType in configuration.NamingNormalizers) |
||||
|
{ |
||||
|
var normalizer = scope.ServiceProvider |
||||
|
.GetRequiredService(normalizerType) |
||||
|
.As<IBlobNamingNormalizer>(); |
||||
|
|
||||
|
containerName = normalizer.NormalizeContainerName(containerName); |
||||
|
} |
||||
|
|
||||
|
return containerName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public interface IBlobContainerRepository : IBasicRepository<BlobContainer, Guid> |
||||
|
{ |
||||
|
Task<bool> ContainerExistsAsync(string name, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<BlobContainer> GetByNameAsync(string name, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<long> GetCountAsync(string filter = "", CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<BlobContainer>> GetPagedListAsync(string filter = "", string sorting = nameof(BlobContainer.Name), |
||||
|
int skipCount = 1, int maxResultCount = 10, CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
public interface IBlobRepository : IBasicRepository<Blob, Guid> |
||||
|
{ |
||||
|
Task<bool> BlobExistsAsync(string sha256, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<Blob> GetBySha256Async(string sha256, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task CopyToAsync(Blob blob, Guid copyToContainerId, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task MoveToAsync(Blob blob, Guid moveToContainerId, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<long> GetCountAsync(Guid containerId, string filter = "", CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Blob>> GetPagedListAsync(Guid containerId, string filter = "", string sorting = nameof(Blob.Name), |
||||
|
int skipCount = 1, int maxResultCount = 10, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Platform.BlobStoring |
||||
|
{ |
||||
|
[BlobContainerName("abp-application-oss")] |
||||
|
public class OSSContainer |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System.Security.Cryptography; |
||||
|
|
||||
|
namespace System |
||||
|
{ |
||||
|
public static class BytesExtensions |
||||
|
{ |
||||
|
public static string Md5(this byte[] data, bool lowercase = false) |
||||
|
{ |
||||
|
using (var md5 = MD5.Create()) |
||||
|
{ |
||||
|
var hashBytes = md5.ComputeHash(data); |
||||
|
var md5Str = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
||||
|
return lowercase ? md5Str.ToLower() : md5Str; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static string Sha1(this byte[] data, bool lowercase = false) |
||||
|
{ |
||||
|
using (var sha = SHA1.Create()) |
||||
|
{ |
||||
|
var hashBytes = sha.ComputeHash(data); |
||||
|
var sha1 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
||||
|
return lowercase ? sha1.ToLower() : sha1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static string Sha256(this byte[] data, bool lowercase = false) |
||||
|
{ |
||||
|
using (var sha = SHA256.Create()) |
||||
|
{ |
||||
|
var hashBytes = sha.ComputeHash(data); |
||||
|
var sha256 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
||||
|
return lowercase ? sha256.ToLower() : sha256; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static string Sha512(this byte[] data, bool lowercase = false) |
||||
|
{ |
||||
|
using (var sha = SHA512.Create()) |
||||
|
{ |
||||
|
var hashBytes = sha.ComputeHash(data); |
||||
|
var sha512 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
||||
|
return lowercase ? sha512.ToLower() : sha512; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="3.0.0" /> |
||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.5" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Abp.EntityFrameworkCore.Tests |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpTestsBaseModule) |
||||
|
)] |
||||
|
public class AbpEntityFrameworkCoreTestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddEntityFrameworkInMemoryDatabase(); |
||||
|
|
||||
|
var databaseName = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
Configure<AbpDbContextOptions>(options => |
||||
|
{ |
||||
|
options.Configure(abpDbContextConfigurationContext => |
||||
|
{ |
||||
|
abpDbContextConfigurationContext.DbContextOptions.UseInMemoryDatabase(databaseName); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpUnitOfWorkDefaultOptions>(options => |
||||
|
{ |
||||
|
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
|
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue