mirror of https://github.com/abpframework/abp.git
145 changed files with 2723 additions and 305 deletions
@ -0,0 +1,67 @@ |
|||||
|
# Switch to EF Core Oracle Provider |
||||
|
|
||||
|
This document explains how to switch to the **Oracle** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured. |
||||
|
|
||||
|
> This document uses a paid library of [Devart](https://www.devart.com/dotconnect/oracle/) company, because it is the only library for Oracle that supports EF Core 3.x. |
||||
|
|
||||
|
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package |
||||
|
|
||||
|
`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.Oracle.Devart](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart) package. |
||||
|
|
||||
|
## Replace the Module Dependency |
||||
|
|
||||
|
Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreOracleDevartModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.Oracle.Devart;`). |
||||
|
|
||||
|
## UseOracle() |
||||
|
|
||||
|
Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: |
||||
|
|
||||
|
* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. |
||||
|
* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. |
||||
|
|
||||
|
|
||||
|
In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block |
||||
|
|
||||
|
``` |
||||
|
var builder = new DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>() |
||||
|
.UseSqlServer(configuration.GetConnectionString("Default")); |
||||
|
``` |
||||
|
|
||||
|
with this one |
||||
|
``` |
||||
|
var builder = (DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>) |
||||
|
new DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>().UseOracle |
||||
|
( |
||||
|
configuration.GetConnectionString("Default") |
||||
|
); |
||||
|
``` |
||||
|
|
||||
|
> Depending on your solution structure, you may find more code files need to be changed. |
||||
|
|
||||
|
## Change the Connection Strings |
||||
|
|
||||
|
Oracle connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/oracle/ ) for details of Oracle connection string options. |
||||
|
|
||||
|
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. |
||||
|
|
||||
|
A sample connection string for Oracle: |
||||
|
``` |
||||
|
Data Source=localhost;User Id=myuser;Password=mypassword; |
||||
|
``` |
||||
|
|
||||
|
## Re-Generate the Migrations |
||||
|
|
||||
|
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) by default. |
||||
|
EF Core Migrations depend on the selected DBMS provider. Changing the DBMS provider, may not work with the existing migrations. |
||||
|
|
||||
|
* Delete the `Migrations` folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. |
||||
|
* Run `Add-Migration "Initial"` on the Package Manager Console window (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). |
||||
|
|
||||
|
This will scaffold a new migration for Oracle. |
||||
|
|
||||
|
Run the `.DbMigrator` project to create the database, apply the changes and seed the initial data. |
||||
|
|
||||
|
## Run the Application |
||||
|
|
||||
|
It is ready. Just run the application and enjoy coding. |
||||
|
|
||||
@ -0,0 +1,73 @@ |
|||||
|
# 切换到EF Core Oracle提供程序 |
||||
|
|
||||
|
本文介绍如何将预配置为SqlServer提供程序的 **[应用程序启动模板](Startup-Templates/Application.md)** 切换到 **Oracle** 数据库提供程序 |
||||
|
|
||||
|
> 本文档使用[Devart](https://www.devart.com/dotconnect/oracle/)公司的付费库,因为它是oracle唯一支持EF Core 3.x的库 |
||||
|
|
||||
|
## 替换Volo.Abp.EntityFrameworkCore.SqlServer包 |
||||
|
|
||||
|
解决方案中的 `.EntityFrameworkCore` 项目依赖于 [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet包. 删除这个包并且添加相同版本的 [Volo.Abp.EntityFrameworkCore.Oracle.Devart](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart) 包. |
||||
|
|
||||
|
## 替换模块依赖项 |
||||
|
|
||||
|
在 `.EntityFrameworkCore` 项目中找到 **YourProjectName*EntityFrameworkCoreModule** 类, 删除 `DependsOn` attribute 上的`typeof(AbpEntityFrameworkCoreSqlServerModule)`, 添加 `typeof(AbpEntityFrameworkCoreOracleDevartModule)` (或者替换 `using Volo.Abp.EntityFrameworkCore.SqlServer;` 为 `using Volo.Abp.EntityFrameworkCore.Oracle.Devart;`). |
||||
|
|
||||
|
## UseOracle() |
||||
|
|
||||
|
Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check the following files: |
||||
|
|
||||
|
* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. |
||||
|
* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. |
||||
|
|
||||
|
In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block |
||||
|
|
||||
|
查找你的解决方案中 `UseSqlServer()`调用,替换为 `UseOracle()`. 检查下列文件: |
||||
|
|
||||
|
* `.EntityFrameworkCore` 项目中的*YourProjectName*EntityFrameworkCoreModule.cs. |
||||
|
* `.EntityFrameworkCore` 项目中的*YourProjectName*MigrationsDbContextFactory.cs. |
||||
|
|
||||
|
使用以下代码替换*YourProjectName*MigrationsDbContextFactory.cs中的 `CreateDbContext()` 方法: |
||||
|
|
||||
|
``` |
||||
|
var builder = new DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>() |
||||
|
.UseSqlServer(configuration.GetConnectionString("Default")); |
||||
|
``` |
||||
|
|
||||
|
与这个 |
||||
|
|
||||
|
``` |
||||
|
var builder = (DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>) |
||||
|
new DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>().UseOracle |
||||
|
( |
||||
|
configuration.GetConnectionString("Default") |
||||
|
); |
||||
|
``` |
||||
|
|
||||
|
> 根据你的解决方案的结构,你可能发现更多需要改变代码的文件. |
||||
|
|
||||
|
## 更改连接字符串 |
||||
|
|
||||
|
Oracle连接字符串与SQL Server连接字符串不同. 所以检查你的解决方案中所有的 `appsettings.json` 文件,更改其中的连接字符串. 有关oracle连接字符串选项的详细内容请参见[connectionstrings.com](https://www.connectionstrings.com/oracle/). |
||||
|
|
||||
|
通常需要更改 `.DbMigrator` 和 `.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构. |
||||
|
|
||||
|
Oracle连接字符串示例: |
||||
|
|
||||
|
``` |
||||
|
Data Source=localhost;User Id=myuser;Password=mypassword; |
||||
|
``` |
||||
|
|
||||
|
## 重新生成迁移 |
||||
|
|
||||
|
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败. |
||||
|
|
||||
|
* 删除 `.EntityFrameworkCore.DbMigrations` 项目下的Migrations文件夹,并重新生成解决方案. |
||||
|
* 在包管理控制台中运行 `Add-Migration "Initial"`(在解决方案资源管理器选择 `.DbMigrator` (或 `.Web`) 做为启动项目并且选择 `.EntityFrameworkCore.DbMigrations` 做为默认项目). |
||||
|
|
||||
|
这将创建一个配置所有数据库对象(表)的数据库迁移. |
||||
|
|
||||
|
运行 `.DbMigrator` 项目创建数据库和初始种子数据. |
||||
|
|
||||
|
## 运行应用程序 |
||||
|
|
||||
|
它已准备就绪, 只需要运行该应用程序与享受编码. |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations |
||||
|
{ |
||||
|
public class ClockDto |
||||
|
{ |
||||
|
public string Kind { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations |
||||
|
{ |
||||
|
public class TimingDto |
||||
|
{ |
||||
|
public TimeZone TimeZone { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class TimeZone |
||||
|
{ |
||||
|
public IanaTimeZone Iana { get; set; } |
||||
|
|
||||
|
public WindowsTimeZone Windows { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class WindowsTimeZone |
||||
|
{ |
||||
|
public string TimeZoneId { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class IanaTimeZone |
||||
|
{ |
||||
|
public string TimeZoneName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,32 @@ |
|||||
using Volo.Abp.Modularity; |
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Localization.Resources.AbpLocalization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Settings; |
||||
|
using Volo.Abp.Timing.Localization.Resources.AbpTiming; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
namespace Volo.Abp.Timing |
namespace Volo.Abp.Timing |
||||
{ |
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpVirtualFileSystemModule), |
||||
|
typeof(AbpSettingsModule) |
||||
|
)] |
||||
public class AbpTimingModule : AbpModule |
public class AbpTimingModule : AbpModule |
||||
{ |
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpTimingModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options |
||||
|
.Resources |
||||
|
.Add<AbpTimingResource>("en") |
||||
|
.AddVirtualJson("/Volo/Abp/Timing/Localization"); |
||||
|
}); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.Timing |
||||
|
{ |
||||
|
public interface ITimezoneProvider |
||||
|
{ |
||||
|
List<NameValue> GetWindowsTimezones(); |
||||
|
|
||||
|
List<NameValue> GetIanaTimezones(); |
||||
|
|
||||
|
string WindowsToIana(string windowsTimeZoneId); |
||||
|
|
||||
|
string IanaToWindows(string ianaTimeZoneName); |
||||
|
|
||||
|
TimeZoneInfo GetTimeZoneInfo(string windowsOrIanaTimeZoneId); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Timing.Localization.Resources.AbpTiming |
||||
|
{ |
||||
|
[LocalizationResourceName("AbpTiming")] |
||||
|
public class AbpTimingResource |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"DisplayName:Abp.Timing.Timezone": "Timezone", |
||||
|
"Description:Abp.Timing.Timezone": "Application time zone" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "tr", |
||||
|
"texts": { |
||||
|
"DisplayName:Abp.Timing.Timezone": "saat dilimi", |
||||
|
"Description:Abp.Timing.Timezone": "Uygulama saat dilimi" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"DisplayName:Abp.Timing.Timezone": "时区", |
||||
|
"Description:Abp.Timing.Timezone": "应用程序的时区" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hant", |
||||
|
"texts": { |
||||
|
"DisplayName:Abp.Timing.Timezone": "時區", |
||||
|
"Description:Abp.Timing.Timezone": "應用程序的時區" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using TimeZoneConverter; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Timing |
||||
|
{ |
||||
|
public class TZConvertTimezoneProvider : ITimezoneProvider, ITransientDependency |
||||
|
{ |
||||
|
public virtual List<NameValue> GetWindowsTimezones() |
||||
|
{ |
||||
|
return TZConvert.KnownIanaTimeZoneNames.OrderBy(x => x).Select(x => new NameValue(x, x)).ToList(); |
||||
|
} |
||||
|
|
||||
|
public virtual List<NameValue> GetIanaTimezones() |
||||
|
{ |
||||
|
return TZConvert.KnownIanaTimeZoneNames.OrderBy(x => x).Select(x => new NameValue(x, x)).ToList(); |
||||
|
} |
||||
|
|
||||
|
public virtual string WindowsToIana(string windowsTimeZoneId) |
||||
|
{ |
||||
|
return TZConvert.WindowsToIana(windowsTimeZoneId); |
||||
|
} |
||||
|
|
||||
|
public virtual string IanaToWindows(string ianaTimeZoneName) |
||||
|
{ |
||||
|
return TZConvert.IanaToWindows(ianaTimeZoneName); |
||||
|
} |
||||
|
|
||||
|
public virtual TimeZoneInfo GetTimeZoneInfo(string windowsOrIanaTimeZoneId) |
||||
|
{ |
||||
|
return TZConvert.GetTimeZoneInfo(windowsOrIanaTimeZoneId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.Timing |
||||
|
{ |
||||
|
public static class TimingSettingNames |
||||
|
{ |
||||
|
public const string TimeZone = "Abp.Timing.TimeZone"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Settings; |
||||
|
using Volo.Abp.Timing.Localization.Resources.AbpTiming; |
||||
|
|
||||
|
namespace Volo.Abp.Timing |
||||
|
{ |
||||
|
public class TimingSettingProvider : SettingDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ISettingDefinitionContext context) |
||||
|
{ |
||||
|
context.Add( |
||||
|
new SettingDefinition(TimingSettingNames.TimeZone, |
||||
|
"UTC", |
||||
|
L("DisplayName:Abp.Timing.Timezone"), |
||||
|
L("Description:Abp.Timing.Timezone"), |
||||
|
isVisibleToClients: true) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpTimingResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
|
||||
|
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
|
# Visual Studio Version 16 |
||||
|
VisualStudioVersion = 16.0.29001.49 |
||||
|
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.Domain.Shared", "src\Volo.Abp.BlobStoring.Database.Domain.Shared\Volo.Abp.BlobStoring.Database.Domain.Shared.csproj", "{D64C1577-4929-4B60-939E-96DE1534891A}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.Domain", "src\Volo.Abp.BlobStoring.Database.Domain\Volo.Abp.BlobStoring.Database.Domain.csproj", "{F2840BC7-0188-4606-9126-DADD0F5ABF7A}" |
||||
|
EndProject |
||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{649A3FFA-182F-4E56-9717-E6A9A2BEC545}" |
||||
|
EndProject |
||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.EntityFrameworkCore", "src\Volo.Abp.BlobStoring.Database.EntityFrameworkCore\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.csproj", "{0CE86223-D31D-4315-A1F5-87BA3EE1B844}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.MongoDB", "src\Volo.Abp.BlobStoring.Database.MongoDB\Volo.Abp.BlobStoring.Database.MongoDB.csproj", "{F1C58097-4C08-4D88-8976-6B3389391481}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.TestBase", "test\Volo.Abp.BlobStoring.Database.TestBase\Volo.Abp.BlobStoring.Database.TestBase.csproj", "{C5BB573D-3030-4BCB-88B7-F6A85C32766C}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.EntityFrameworkCore.Tests", "test\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.Tests\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.Tests.csproj", "{527F645C-C1FC-406E-8479-81386C8ECF13}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.MongoDB.Tests", "test\Volo.Abp.BlobStoring.Database.MongoDB.Tests\Volo.Abp.BlobStoring.Database.MongoDB.Tests.csproj", "{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}" |
||||
|
EndProject |
||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Database.Domain.Tests", "test\Volo.Abp.BlobStoring.Database.Domain.Tests\Volo.Abp.BlobStoring.Database.Domain.Tests.csproj", "{E60895E5-79C4-447D-88B7-85CB5BA336A4}" |
||||
|
EndProject |
||||
|
Global |
||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
|
Debug|Any CPU = Debug|Any CPU |
||||
|
Release|Any CPU = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
|
EndGlobalSection |
||||
|
GlobalSection(SolutionProperties) = preSolution |
||||
|
HideSolutionNode = FALSE |
||||
|
EndGlobalSection |
||||
|
GlobalSection(NestedProjects) = preSolution |
||||
|
{D64C1577-4929-4B60-939E-96DE1534891A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{0CE86223-D31D-4315-A1F5-87BA3EE1B844} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{F1C58097-4C08-4D88-8976-6B3389391481} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} |
||||
|
{C5BB573D-3030-4BCB-88B7-F6A85C32766C} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{527F645C-C1FC-406E-8479-81386C8ECF13} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
{E60895E5-79C4-447D-88B7-85CB5BA336A4} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
|
SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD} |
||||
|
EndGlobalSection |
||||
|
EndGlobal |
||||
@ -0,0 +1,23 @@ |
|||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
||||
|
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceIfStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceLockStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String> |
||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String> |
||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String> |
||||
|
</wpf:ResourceDictionary> |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\..\abp\framework\src\Volo.Abp.Validation\Volo.Abp.Validation.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="Volo\Abp\BlobStoring\Database\Localization\*.json" /> |
||||
|
<Content Remove="Volo\Abp\BlobStoring\Database\Localization\*.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,37 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.BlobStoring.Database.Localization; |
||||
|
using Volo.Abp.Localization.ExceptionHandling; |
||||
|
using Volo.Abp.Validation; |
||||
|
using Volo.Abp.Validation.Localization; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpValidationModule) |
||||
|
)] |
||||
|
public class BlobStoringDatabaseDomainSharedModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<BlobStoringDatabaseDomainSharedModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<BlobStoringDatabaseResource>("en") |
||||
|
.AddBaseTypes(typeof(AbpValidationResource)) |
||||
|
.AddVirtualJson("/Volo/Abp/BlobStoring/Database/Localization"); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpExceptionLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.MapCodeNamespace("BlobStoringDatabase", typeof(BlobStoringDatabaseResource)); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public static class BlobStoringDatabaseErrorCodes |
||||
|
{ |
||||
|
//Add your business exception error codes here...
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public static class DatabaseBlobConsts |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default value: 256.
|
||||
|
/// </summary>
|
||||
|
public static int MaxNameLength { get; set; } = 256; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Default value: <see cref="int.MaxValue"/> (2GB).
|
||||
|
/// </summary>
|
||||
|
public static int MaxContentLength { get; set; } = int.MaxValue; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public static class DatabaseContainerConsts |
||||
|
{ |
||||
|
public const int MaxNameLength = 128; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("BlobStoringDatabase")] |
||||
|
public class BlobStoringDatabaseResource |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "cs", |
||||
|
"texts": { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"ManageYourProfile": "Manage your profile" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "pl-PL", |
||||
|
"texts": { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "pt-BR", |
||||
|
"texts": { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "sl", |
||||
|
"texts": { |
||||
|
"ManageYourProfile": "Upravljajte svojim profilom" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "tr", |
||||
|
"texts": { |
||||
|
"ManageYourProfile": "Profil yönetimi" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "vi", |
||||
|
"texts": { |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"ManageYourProfile": "管理个人资料" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hant", |
||||
|
"texts": { |
||||
|
"ManageYourProfile": "管理個人資料" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,17 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\..\abp\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" /> |
||||
|
<ProjectReference Include="..\..\..\..\..\abp\framework\src\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Database.Domain.Shared\Volo.Abp.BlobStoring.Database.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public static class BlobStoringDatabaseDbProperties |
||||
|
{ |
||||
|
public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix; |
||||
|
|
||||
|
public static string DbSchema { get; set; } = AbpCommonDbProperties.DbSchema; |
||||
|
|
||||
|
public const string ConnectionStringName = "AbpBlobStoring"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.Domain; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDddDomainModule), |
||||
|
typeof(AbpBlobStoringModule), |
||||
|
typeof(BlobStoringDatabaseDomainSharedModule) |
||||
|
)] |
||||
|
public class BlobStoringDatabaseDomainModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public class DatabaseBlob : AggregateRoot<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 byte[] Content { get; protected set; } |
||||
|
|
||||
|
public DatabaseBlob(Guid id, Guid containerId, [NotNull] string name, [NotNull] byte[] content, Guid? tenantId = null) |
||||
|
: base(id) |
||||
|
{ |
||||
|
Name = Check.NotNullOrWhiteSpace(name, nameof(name), DatabaseBlobConsts.MaxNameLength); |
||||
|
ContainerId = containerId; |
||||
|
Content = CheckContentLength(content); |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
public virtual void SetContent(byte[] content) |
||||
|
{ |
||||
|
Content = CheckContentLength(content); |
||||
|
} |
||||
|
|
||||
|
protected virtual byte[] CheckContentLength(byte[] content) |
||||
|
{ |
||||
|
Check.NotNull(content, nameof(content)); |
||||
|
|
||||
|
if (content.Length >= DatabaseBlobConsts.MaxContentLength) |
||||
|
{ |
||||
|
throw new AbpException($"Blob content size cannot be more than {DatabaseBlobConsts.MaxContentLength} Bytes."); |
||||
|
} |
||||
|
|
||||
|
return content; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public class DatabaseBlobContainer : AggregateRoot<Guid>, IMultiTenant //TODO: Rename to BlobContainer
|
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual string Name { get; protected set; } |
||||
|
|
||||
|
public DatabaseBlobContainer(Guid id, [NotNull] string name, Guid? tenantId = null) |
||||
|
: base(id) |
||||
|
{ |
||||
|
Name = Check.NotNullOrWhiteSpace(name, nameof(name), DatabaseContainerConsts.MaxNameLength); |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public static class DatabaseBlobContainerConfigurationExtensions |
||||
|
{ |
||||
|
public static BlobContainerConfiguration UseDatabase( |
||||
|
this BlobContainerConfiguration containerConfiguration) |
||||
|
{ |
||||
|
containerConfiguration.ProviderType = typeof(DatabaseBlobProvider); |
||||
|
return containerConfiguration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,120 @@ |
|||||
|
using System.IO; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public class DatabaseBlobProvider : BlobProviderBase, ITransientDependency |
||||
|
{ |
||||
|
protected IDatabaseBlobRepository DatabaseBlobRepository { get; } |
||||
|
protected IDatabaseBlobContainerRepository DatabaseBlobContainerRepository { get; } |
||||
|
protected IGuidGenerator GuidGenerator { get; } |
||||
|
|
||||
|
public DatabaseBlobProvider( |
||||
|
IDatabaseBlobRepository databaseBlobRepository, |
||||
|
IDatabaseBlobContainerRepository databaseBlobContainerRepository, |
||||
|
IGuidGenerator guidGenerator) |
||||
|
{ |
||||
|
DatabaseBlobRepository = databaseBlobRepository; |
||||
|
DatabaseBlobContainerRepository = databaseBlobContainerRepository; |
||||
|
GuidGenerator = guidGenerator; |
||||
|
} |
||||
|
|
||||
|
public override async Task SaveAsync(BlobProviderSaveArgs args) |
||||
|
{ |
||||
|
var container = await GetOrCreateContainerAsync(args.ContainerName, args.CancellationToken); |
||||
|
|
||||
|
var blob = await DatabaseBlobRepository.FindAsync(container.Id, args.BlobName, |
||||
|
args.CancellationToken); |
||||
|
|
||||
|
var content = await args.BlobStream.GetAllBytesAsync(args.CancellationToken); |
||||
|
|
||||
|
if (blob != null) |
||||
|
{ |
||||
|
if (!args.OverrideExisting) |
||||
|
{ |
||||
|
throw new BlobAlreadyExistsException( |
||||
|
$"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); |
||||
|
} |
||||
|
|
||||
|
blob.SetContent(content); |
||||
|
await DatabaseBlobRepository.UpdateAsync(blob); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
blob = new DatabaseBlob(GuidGenerator.Create(), container.Id, args.BlobName, content); |
||||
|
await DatabaseBlobRepository.InsertAsync(blob); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
||||
|
{ |
||||
|
var container = |
||||
|
await DatabaseBlobContainerRepository.FindAsync(args.ContainerName, |
||||
|
args.CancellationToken); |
||||
|
|
||||
|
if (container == null) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return await DatabaseBlobRepository.DeleteAsync(container.Id, args.BlobName, |
||||
|
args.CancellationToken); |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
||||
|
{ |
||||
|
var container = |
||||
|
await DatabaseBlobContainerRepository.FindAsync(args.ContainerName, |
||||
|
args.CancellationToken); |
||||
|
|
||||
|
if (container == null) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return await DatabaseBlobRepository.ExistsAsync(container.Id, args.BlobName, |
||||
|
args.CancellationToken); |
||||
|
} |
||||
|
|
||||
|
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
||||
|
{ |
||||
|
var container = |
||||
|
await DatabaseBlobContainerRepository.FindAsync(args.ContainerName, |
||||
|
args.CancellationToken); |
||||
|
|
||||
|
if (container == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var blob = await DatabaseBlobRepository.FindAsync(container.Id, args.BlobName, |
||||
|
args.CancellationToken); |
||||
|
|
||||
|
if (blob == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return new MemoryStream(blob.Content); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<DatabaseBlobContainer> GetOrCreateContainerAsync( |
||||
|
string name, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var container = await DatabaseBlobContainerRepository.FindAsync(name, cancellationToken); |
||||
|
if (container != null) |
||||
|
{ |
||||
|
return container; |
||||
|
} |
||||
|
|
||||
|
container = new DatabaseBlobContainer(GuidGenerator.Create(), name); |
||||
|
await DatabaseBlobContainerRepository.InsertAsync(container, cancellationToken: cancellationToken); |
||||
|
|
||||
|
return container; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public interface IDatabaseBlobContainerRepository : IBasicRepository<DatabaseBlobContainer, Guid> |
||||
|
{ |
||||
|
Task<DatabaseBlobContainer> FindAsync([NotNull] string name, CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
public interface IDatabaseBlobRepository : IBasicRepository<DatabaseBlob, Guid> |
||||
|
{ |
||||
|
Task<DatabaseBlob> FindAsync(Guid containerId, [NotNull] string name, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<bool> ExistsAsync(Guid containerId, [NotNull] string name, CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<bool> DeleteAsync(Guid containerId, [NotNull] string name, CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\..\abp\framework\src\Volo.Abp.EntityFrameworkCore\Volo.Abp.EntityFrameworkCore.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Database.Domain\Volo.Abp.BlobStoring.Database.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(BlobStoringDatabaseDomainModule), |
||||
|
typeof(AbpEntityFrameworkCoreModule) |
||||
|
)] |
||||
|
public class BlobStoringDatabaseEntityFrameworkCoreModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAbpDbContext<BlobStoringDbContext>(options => |
||||
|
{ |
||||
|
options.AddRepository<DatabaseBlobContainer, EfCoreDatabaseBlobContainerRepository>(); |
||||
|
|
||||
|
options.AddRepository<DatabaseBlob, EfCoreDatabaseBlobRepository>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] |
||||
|
public class BlobStoringDbContext : AbpDbContext<BlobStoringDbContext>, IBlobStoringDbContext |
||||
|
{ |
||||
|
public DbSet<DatabaseBlobContainer> BlobContainers { get; set; } |
||||
|
|
||||
|
public DbSet<DatabaseBlob> Blobs { get; set; } |
||||
|
|
||||
|
public BlobStoringDbContext(DbContextOptions<BlobStoringDbContext> options) |
||||
|
: base(options) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
protected override void OnModelCreating(ModelBuilder builder) |
||||
|
{ |
||||
|
base.OnModelCreating(builder); |
||||
|
|
||||
|
builder.ConfigureBlobStoring(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
public static class BlobStoringDbContextModelCreatingExtensions |
||||
|
{ |
||||
|
public static void ConfigureBlobStoring( |
||||
|
this ModelBuilder builder, |
||||
|
Action<BlobStoringModelBuilderConfigurationOptions> optionsAction = null) |
||||
|
{ |
||||
|
Check.NotNull(builder, nameof(builder)); |
||||
|
|
||||
|
var options = new BlobStoringModelBuilderConfigurationOptions( |
||||
|
BlobStoringDatabaseDbProperties.DbTablePrefix, |
||||
|
BlobStoringDatabaseDbProperties.DbSchema |
||||
|
); |
||||
|
|
||||
|
optionsAction?.Invoke(options); |
||||
|
|
||||
|
builder.Entity<DatabaseBlobContainer>(b => |
||||
|
{ |
||||
|
b.ToTable(options.TablePrefix + "BlobContainers", options.Schema); |
||||
|
|
||||
|
b.ConfigureByConvention(); |
||||
|
|
||||
|
b.Property(p => p.Name).IsRequired().HasMaxLength(DatabaseContainerConsts.MaxNameLength); |
||||
|
|
||||
|
b.HasIndex(x => new {x.TenantId, x.Name}); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<DatabaseBlob>(b => |
||||
|
{ |
||||
|
b.ToTable(options.TablePrefix + "Blobs", options.Schema); |
||||
|
|
||||
|
b.ConfigureByConvention(); |
||||
|
|
||||
|
b.Property(p => p.ContainerId).IsRequired(); //TODO: Foreign key!
|
||||
|
b.Property(p => p.Name).IsRequired().HasMaxLength(DatabaseBlobConsts.MaxNameLength); |
||||
|
b.Property(p => p.Content).HasMaxLength(DatabaseBlobConsts.MaxContentLength); |
||||
|
|
||||
|
b.HasIndex(x => new {x.TenantId, x.ContainerId, x.Name}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
public class BlobStoringModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions |
||||
|
{ |
||||
|
public BlobStoringModelBuilderConfigurationOptions( |
||||
|
[NotNull] string tablePrefix = "", |
||||
|
[CanBeNull] string schema = null) |
||||
|
: base( |
||||
|
tablePrefix, |
||||
|
schema) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
public class EfCoreDatabaseBlobContainerRepository : EfCoreRepository<IBlobStoringDbContext, DatabaseBlobContainer, Guid>, IDatabaseBlobContainerRepository |
||||
|
{ |
||||
|
public EfCoreDatabaseBlobContainerRepository(IDbContextProvider<IBlobStoringDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<DatabaseBlobContainer> FindAsync(string name, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet.FirstOrDefaultAsync(x => x.Name == name, GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
public class EfCoreDatabaseBlobRepository : EfCoreRepository<IBlobStoringDbContext, DatabaseBlob, Guid>, IDatabaseBlobRepository |
||||
|
{ |
||||
|
public EfCoreDatabaseBlobRepository(IDbContextProvider<IBlobStoringDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<DatabaseBlob> FindAsync( |
||||
|
Guid containerId, |
||||
|
string name, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet.FirstOrDefaultAsync( |
||||
|
x => x.ContainerId == containerId && x.Name == name, |
||||
|
GetCancellationToken(cancellationToken) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> ExistsAsync( |
||||
|
Guid containerId, |
||||
|
string name, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet.AnyAsync( |
||||
|
x => x.ContainerId == containerId && x.Name == name, |
||||
|
GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> DeleteAsync( |
||||
|
Guid containerId, |
||||
|
string name, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var blob = await FindAsync(containerId, name, cancellationToken); |
||||
|
if (blob == null) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
await base.DeleteAsync(blob.Id, cancellationToken: GetCancellationToken(cancellationToken)); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] |
||||
|
public interface IBlobStoringDbContext : IEfCoreDbContext |
||||
|
{ |
||||
|
DbSet<DatabaseBlobContainer> BlobContainers { get; } |
||||
|
|
||||
|
DbSet<DatabaseBlob> Blobs { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\..\abp\framework\src\Volo.Abp.MongoDB\Volo.Abp.MongoDB.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Database.Domain\Volo.Abp.BlobStoring.Database.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,22 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(BlobStoringDatabaseDomainModule), |
||||
|
typeof(AbpMongoDbModule) |
||||
|
)] |
||||
|
public class BlobStoringDatabaseMongoDbModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddMongoDbContext<BlobStoringMongoDbContext>(options => |
||||
|
{ |
||||
|
options.AddRepository<DatabaseBlobContainer, MongoDbDatabaseBlobContainerRepository>(); |
||||
|
options.AddRepository<DatabaseBlob, MongoDbDatabaseBlobRepository>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using MongoDB.Driver; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] |
||||
|
public class BlobStoringMongoDbContext : AbpMongoDbContext, IBlobStoringMongoDbContext |
||||
|
{ |
||||
|
public IMongoCollection<DatabaseBlobContainer> BlobContainers => Collection<DatabaseBlobContainer>(); |
||||
|
|
||||
|
public IMongoCollection<DatabaseBlob> Blobs => Collection<DatabaseBlob>(); |
||||
|
|
||||
|
protected override void CreateModel(IMongoModelBuilder modelBuilder) |
||||
|
{ |
||||
|
base.CreateModel(modelBuilder); |
||||
|
|
||||
|
modelBuilder.ConfigureBlobStoring(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
public static class BlobStoringMongoDbContextExtensions |
||||
|
{ |
||||
|
public static void ConfigureBlobStoring( |
||||
|
this IMongoModelBuilder builder, |
||||
|
Action<AbpMongoModelBuilderConfigurationOptions> optionsAction = null) |
||||
|
{ |
||||
|
Check.NotNull(builder, nameof(builder)); |
||||
|
|
||||
|
var options = new BlobStoringMongoModelBuilderConfigurationOptions( |
||||
|
BlobStoringDatabaseDbProperties.DbTablePrefix |
||||
|
); |
||||
|
|
||||
|
optionsAction?.Invoke(options); |
||||
|
|
||||
|
builder.Entity<DatabaseBlobContainer>(b => |
||||
|
{ |
||||
|
b.CollectionName = options.CollectionPrefix + "BlobContainers"; |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<DatabaseBlob>(b => |
||||
|
{ |
||||
|
b.CollectionName = options.CollectionPrefix + "Blobs"; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
public class BlobStoringMongoModelBuilderConfigurationOptions : AbpMongoModelBuilderConfigurationOptions |
||||
|
{ |
||||
|
public BlobStoringMongoModelBuilderConfigurationOptions( |
||||
|
[NotNull] string collectionPrefix = "") |
||||
|
: base(collectionPrefix) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using MongoDB.Driver; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] |
||||
|
public interface IBlobStoringMongoDbContext : IAbpMongoDbContext |
||||
|
{ |
||||
|
IMongoCollection<DatabaseBlobContainer> BlobContainers { get; } |
||||
|
|
||||
|
IMongoCollection<DatabaseBlob> Blobs { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.MongoDB; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
public class MongoDbDatabaseBlobContainerRepository : MongoDbRepository<IBlobStoringMongoDbContext, DatabaseBlobContainer, Guid>, IDatabaseBlobContainerRepository |
||||
|
{ |
||||
|
public MongoDbDatabaseBlobContainerRepository(IMongoDbContextProvider<IBlobStoringMongoDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<DatabaseBlobContainer> FindAsync(string name, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await base.FindAsync(x => x.Name == name, cancellationToken: GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using MongoDB.Driver.Linq; |
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.MongoDB; |
||||
|
using Volo.Abp.MongoDB; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database.MongoDB |
||||
|
{ |
||||
|
public class MongoDbDatabaseBlobRepository : MongoDbRepository<IBlobStoringMongoDbContext, DatabaseBlob, Guid>, IDatabaseBlobRepository |
||||
|
{ |
||||
|
public MongoDbDatabaseBlobRepository(IMongoDbContextProvider<IBlobStoringMongoDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<DatabaseBlob> FindAsync(Guid containerId, string name, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await GetMongoQueryable().FirstOrDefaultAsync( |
||||
|
x => x.ContainerId == containerId && |
||||
|
x.Name == name, |
||||
|
GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> ExistsAsync(Guid containerId, string name, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await GetMongoQueryable().AnyAsync( |
||||
|
x => x.ContainerId == containerId && |
||||
|
x.Name == name, |
||||
|
GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> DeleteAsync(Guid containerId, string name, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var blob = await FindAsync(containerId, name, cancellationToken); |
||||
|
|
||||
|
if (blob == null) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
await base.DeleteAsync(blob, cancellationToken: GetCancellationToken(cancellationToken)); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
/* Inherit from this class for your domain layer tests. |
||||
|
* See SampleManager_Tests for example. |
||||
|
*/ |
||||
|
public abstract class BlobStoringDatabaseDomainTestBase : BlobStoringDatabaseTestBase<BlobStoringDatabaseDomainTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Database |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(BlobStoringDatabaseEntityFrameworkCoreTestModule) |
||||
|
)] |
||||
|
public class BlobStoringDatabaseDomainTestModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace>Volo.Abp.BlobStoring.Database</RootNamespace> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.Tests\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore |
||||
|
{ |
||||
|
public abstract class BlobStoringDatabaseEntityFrameworkCoreTestBase : BlobStoringDatabaseTestBase<BlobStoringDatabaseEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue