@ -1,40 +0,0 @@ |
|||
## Textové soubory pro lokalizaci |
|||
|
|||
Toto je seznam lokalizačních textových souborů pro každého kdo chce přispět k překladu textů ve frameworku. Tento seznam budeme udržovat aktuální: |
|||
|
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json |
|||
@ -1,31 +0,0 @@ |
|||
## Localization Text Files |
|||
|
|||
Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date: |
|||
|
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json |
|||
* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json |
|||
* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json |
|||
@ -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/mysql/ ) 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,80 @@ |
|||
# Virtual File Explorer Module |
|||
|
|||
## What is Virtual File Explorer Module? |
|||
|
|||
Virtual File Explorer Module provided a simple UI to view all files in [virtual file system](../Virtual-File-System.md). |
|||
|
|||
> Virtual File Explorer Module is not installed for [the startup templates](../Startup-Templates/Index.md). So, you need to manually add this module to your application. |
|||
|
|||
### Installation |
|||
|
|||
#### 1- Referencing Virtual File Explorer Module Packages |
|||
|
|||
It is recommended to use the ABP CLI to install the module, open the CMD window in the solution file (`.sln`) directory, and run the following command: |
|||
|
|||
`abp add-module Volo.VirtualFileExplorer` |
|||
|
|||
Or you can also manually install nuget package to `Acme.MyProject.Web` project: |
|||
|
|||
* Install [Volo.Abp.VirtualFileExplorer.Web](https://www.nuget.org/packages/Volo.Abp.VirtualFileExplorer.Web/) nuget package to `Acme.MyProject.Web` project. |
|||
|
|||
`Install-Package Volo.Abp.VirtualFileExplorer.Web` |
|||
|
|||
#### 2- Adding Module Dependencies |
|||
|
|||
* Open `MyProjectWebModule.cs`and add `typeof(AbpVirtualFileExplorerWebModule)` as shown below; |
|||
|
|||
```csharp |
|||
[DependsOn( |
|||
typeof(AbpVirtualFileExplorerWebModule), |
|||
typeof(MyProjectApplicationModule), |
|||
typeof(MyProjectEntityFrameworkCoreModule), |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpIdentityWebModule), |
|||
typeof(AbpAccountWebModule), |
|||
typeof(AbpAspNetCoreMvcUiBasicThemeModule) |
|||
)] |
|||
public class MyProjectWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
``` |
|||
|
|||
#### 3- Adding NPM Package |
|||
|
|||
* Open `package.json` and add `@abp/virtual-file-explorer": "^2.9.0` as shown below: |
|||
|
|||
```json |
|||
{ |
|||
"version": "1.0.0", |
|||
"name": "my-app", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@abp/aspnetcore.mvc.ui.theme.basic": "^2.9.0", |
|||
"@abp/virtual-file-explorer": "^2.9.0" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command: |
|||
|
|||
1. `yarn` |
|||
2. `gulp` |
|||
|
|||
That's all,Now run the application and Navigate to `/VirtualFileExplorer`. You will see virtual file explorer page: |
|||
|
|||
 |
|||
|
|||
### Options |
|||
|
|||
You can disabled virtual file explorer module via `AbpVirtualFileExplorerOptions` options: |
|||
|
|||
```csharp |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<AbpVirtualFileExplorerOptions>(options => |
|||
{ |
|||
options.IsEnabled = false; |
|||
}); |
|||
} |
|||
``` |
|||
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 47 KiB |
@ -1,31 +0,0 @@ |
|||
## 本地化文本文件 |
|||
|
|||
这是一个来自框架的本地化文本文件列表, 任何人都可以做出贡献. 我们会将此列表保持最新: |
|||
|
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json |
|||
* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json |
|||
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json |
|||
* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json |
|||
* https://github.com/abpframework/abp-samples/tree/master/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json |
|||
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json |
|||
* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json |
|||
@ -0,0 +1,80 @@ |
|||
# 虚拟文件浏览器模块 |
|||
|
|||
## 什么是虚拟文件浏览器模块 |
|||
|
|||
虚拟文件浏览器模块提供了一个简单的UI来查看[虚拟文件系统](../Virtual-File-System.md)所有的文件. |
|||
|
|||
> [启动模板](../Startup-Templates/Index.md)默认并没有安装这个模块,所以你需要手动安装到应用程序. |
|||
|
|||
### 安装 |
|||
|
|||
#### 1- 引用虚拟文件浏览器模块包 |
|||
|
|||
建议使用ABP CLI安装模块,在解决方案文件 (`.sln`) 目录打开 `CMD` 窗口,运行以下命令: |
|||
|
|||
`abp add-module Volo.VirtualFileExplorer` |
|||
|
|||
或者你也可以手动安装nuget包到 `Acme.MyProject.Web` 项目: |
|||
|
|||
* 安装[Volo.Abp.VirtualFileExplorer.Web](https://www.nuget.org/packages/Volo.Abp.VirtualFileExplorer.Web/) nuget包到 `Acme.MyProject.Web` 项目. |
|||
|
|||
`Install-Package Volo.Abp.VirtualFileExplorer.Web` |
|||
|
|||
#### 2- 添加模块依赖 |
|||
|
|||
* 打开 `MyProjectWebModule.cs` 并且添加 `typeof(AbpVirtualFileExplorerWebModule)` 如下所示; |
|||
|
|||
```csharp |
|||
[DependsOn( |
|||
typeof(AbpVirtualFileExplorerWebModule), |
|||
typeof(MyProjectApplicationModule), |
|||
typeof(MyProjectEntityFrameworkCoreModule), |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpIdentityWebModule), |
|||
typeof(AbpAccountWebModule), |
|||
typeof(AbpAspNetCoreMvcUiBasicThemeModule) |
|||
)] |
|||
public class MyProjectWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
``` |
|||
|
|||
#### 3- 添加NPM包 |
|||
|
|||
* 打开 `package.json` 添加 `@abp/virtual-file-explorer": "^2.9.0` 如下所示: |
|||
|
|||
```json |
|||
{ |
|||
"version": "1.0.0", |
|||
"name": "my-app", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@abp/aspnetcore.mvc.ui.theme.basic": "^2.9.0", |
|||
"@abp/virtual-file-explorer": "^2.9.0" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令: |
|||
|
|||
1. `yarn` |
|||
2. `gulp` |
|||
|
|||
这就是全部,运行应用程序导航到 `/VirtualFileExplorer`. 你会看到虚拟文件浏览器页面: |
|||
|
|||
 |
|||
|
|||
### 选项 |
|||
|
|||
你可以通过 `AbpVirtualFileExplorerOptions` 选项禁用虚拟文件浏览器模块: |
|||
|
|||
```csharp |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<AbpVirtualFileExplorerOptions>(options => |
|||
{ |
|||
options.IsEnabled = false; |
|||
}); |
|||
} |
|||
``` |
|||
|
After Width: | Height: | Size: 47 KiB |
@ -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,21 +1,72 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Theming; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars |
|||
{ |
|||
public class ToolbarConfigurationContext : IToolbarConfigurationContext |
|||
{ |
|||
public IServiceProvider ServiceProvider { get; } |
|||
private readonly object _serviceProviderLock = new object(); |
|||
|
|||
private TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference) |
|||
{ |
|||
if (reference == null) |
|||
{ |
|||
lock (_serviceProviderLock) |
|||
{ |
|||
if (reference == null) |
|||
{ |
|||
reference = (TRef)ServiceProvider.GetRequiredService(serviceType); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return reference; |
|||
} |
|||
|
|||
public IAuthorizationService AuthorizationService => LazyGetRequiredService(typeof(IAuthorizationService), ref _authorizationService); |
|||
private IAuthorizationService _authorizationService; |
|||
|
|||
private IStringLocalizerFactory _stringLocalizerFactory; |
|||
public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(typeof(IStringLocalizerFactory),ref _stringLocalizerFactory); |
|||
|
|||
public ITheme Theme { get; } |
|||
|
|||
public Toolbar Toolbar { get; } |
|||
|
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public ToolbarConfigurationContext(ITheme currentTheme, Toolbar toolbar, IServiceProvider serviceProvider) |
|||
{ |
|||
Theme = currentTheme; |
|||
Toolbar = toolbar; |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
|
|||
public Task<bool> IsGrantedAsync(string policyName) |
|||
{ |
|||
return AuthorizationService.IsGrantedAsync(policyName); |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public IStringLocalizer GetDefaultLocalizer() |
|||
{ |
|||
return StringLocalizerFactory.CreateDefaultOrNull(); |
|||
} |
|||
|
|||
[NotNull] |
|||
public IStringLocalizer GetLocalizer<T>() |
|||
{ |
|||
return StringLocalizerFactory.Create<T>(); |
|||
} |
|||
|
|||
[NotNull] |
|||
public IStringLocalizer GetLocalizer(Type resourceType) |
|||
{ |
|||
return StringLocalizerFactory.Create(resourceType); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -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,21 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.BlobStoring.FileSystem</AssemblyName> |
|||
<PackageId>Volo.Abp.BlobStoring.FileSystem</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpBlobStoringModule) |
|||
)] |
|||
public class AbpBlobStoringFileSystemModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System.IO; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class DefaultBlobFilePathCalculator : IBlobFilePathCalculator, ITransientDependency |
|||
{ |
|||
public virtual string Calculate(BlobProviderArgs args) |
|||
{ |
|||
var fileSystemConfiguration = args.Configuration.GetFileSystemConfiguration(); |
|||
var blobPath = fileSystemConfiguration.BasePath; |
|||
|
|||
if (args.TenantId == null) |
|||
{ |
|||
blobPath = Path.Combine(blobPath, "host"); |
|||
} |
|||
else |
|||
{ |
|||
blobPath = Path.Combine(blobPath, "tenants", args.TenantId.Value.ToString("D")); |
|||
} |
|||
|
|||
if (fileSystemConfiguration.AppendContainerNameToBasePath) |
|||
{ |
|||
blobPath = Path.Combine(blobPath, args.ContainerName); |
|||
} |
|||
|
|||
blobPath = Path.Combine(blobPath, args.BlobName); |
|||
|
|||
return blobPath; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public static class FileSystemBlobContainerConfigurationExtensions |
|||
{ |
|||
public static FileSystemBlobProviderConfiguration GetFileSystemConfiguration( |
|||
this BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
return new FileSystemBlobProviderConfiguration(containerConfiguration); |
|||
} |
|||
|
|||
public static BlobContainerConfiguration UseFileSystem( |
|||
this BlobContainerConfiguration containerConfiguration, |
|||
Action<FileSystemBlobProviderConfiguration> fileSystemConfigureAction) |
|||
{ |
|||
containerConfiguration.ProviderType = typeof(FileSystemBlobProvider); |
|||
|
|||
fileSystemConfigureAction(new FileSystemBlobProviderConfiguration(containerConfiguration)); |
|||
|
|||
return containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.IO; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class FileSystemBlobProvider : BlobProviderBase, ITransientDependency |
|||
{ |
|||
protected IBlobFilePathCalculator FilePathCalculator { get; } |
|||
|
|||
public FileSystemBlobProvider(IBlobFilePathCalculator filePathCalculator) |
|||
{ |
|||
FilePathCalculator = filePathCalculator; |
|||
} |
|||
|
|||
public override async Task SaveAsync(BlobProviderSaveArgs args) |
|||
{ |
|||
var filePath = FilePathCalculator.Calculate(args); |
|||
|
|||
if (!args.OverrideExisting && await ExistsAsync(filePath)) |
|||
{ |
|||
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); |
|||
} |
|||
|
|||
DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(filePath)); |
|||
|
|||
var fileMode = args.OverrideExisting |
|||
? FileMode.Create |
|||
: FileMode.CreateNew; |
|||
|
|||
using (var fileStream = File.Open(filePath, fileMode, FileAccess.Write)) |
|||
{ |
|||
await args.BlobStream.CopyToAsync( |
|||
fileStream, |
|||
args.CancellationToken |
|||
); |
|||
|
|||
await fileStream.FlushAsync(); |
|||
} |
|||
} |
|||
|
|||
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
|||
{ |
|||
var filePath = FilePathCalculator.Calculate(args); |
|||
return Task.FromResult(FileHelper.DeleteIfExists(filePath)); |
|||
} |
|||
|
|||
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
|||
{ |
|||
var filePath = FilePathCalculator.Calculate(args); |
|||
return ExistsAsync(filePath); |
|||
} |
|||
|
|||
public override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
|||
{ |
|||
var filePath = FilePathCalculator.Calculate(args); |
|||
|
|||
if (!File.Exists(filePath)) |
|||
{ |
|||
return Task.FromResult<Stream>(null); |
|||
} |
|||
|
|||
return Task.FromResult<Stream>(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)); |
|||
} |
|||
|
|||
protected virtual Task<bool> ExistsAsync(string filePath) |
|||
{ |
|||
return Task.FromResult(File.Exists(filePath)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class FileSystemBlobProviderConfiguration |
|||
{ |
|||
public string BasePath |
|||
{ |
|||
get => _containerConfiguration.GetConfiguration<string>(FileSystemBlobProviderConfigurationNames.BasePath); |
|||
set => _containerConfiguration.SetConfiguration(FileSystemBlobProviderConfigurationNames.BasePath, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Default value: true.
|
|||
/// </summary>
|
|||
public bool AppendContainerNameToBasePath |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(FileSystemBlobProviderConfigurationNames.AppendContainerNameToBasePath, true); |
|||
set => _containerConfiguration.SetConfiguration(FileSystemBlobProviderConfigurationNames.AppendContainerNameToBasePath, value); |
|||
} |
|||
|
|||
private readonly BlobContainerConfiguration _containerConfiguration; |
|||
|
|||
public FileSystemBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
_containerConfiguration = containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public static class FileSystemBlobProviderConfigurationNames |
|||
{ |
|||
public const string BasePath = "FileSystem.BasePath"; |
|||
public const string AppendContainerNameToBasePath = "FileSystem.AppendContainerNameToBasePath"; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public interface IBlobFilePathCalculator |
|||
{ |
|||
string Calculate(BlobProviderArgs args); |
|||
} |
|||
} |
|||
@ -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,23 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.BlobStoring</AssemblyName> |
|||
<PackageId>Volo.Abp.BlobStoring</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,28 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpMultiTenancyModule), |
|||
typeof(AbpThreadingModule) |
|||
)] |
|||
public class AbpBlobStoringModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddTransient( |
|||
typeof(IBlobContainer<>), |
|||
typeof(BlobContainer<>) |
|||
); |
|||
|
|||
context.Services.AddTransient( |
|||
typeof(IBlobContainer), |
|||
serviceProvider => serviceProvider |
|||
.GetRequiredService<IBlobContainer<DefaultContainer>>() |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class AbpBlobStoringOptions |
|||
{ |
|||
public BlobContainerConfigurations Containers { get; } |
|||
|
|||
public AbpBlobStoringOptions() |
|||
{ |
|||
Containers = new BlobContainerConfigurations(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobAlreadyExistsException : AbpException |
|||
{ |
|||
public BlobAlreadyExistsException() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public BlobAlreadyExistsException(string message) |
|||
: base(message) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public BlobAlreadyExistsException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public BlobAlreadyExistsException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,198 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainer<TContainer> : IBlobContainer<TContainer> |
|||
where TContainer : class |
|||
{ |
|||
private readonly IBlobContainer _container; |
|||
|
|||
public BlobContainer(IBlobContainerFactory blobContainerFactory) |
|||
{ |
|||
_container = blobContainerFactory.Create<TContainer>(); |
|||
} |
|||
|
|||
public Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.SaveAsync( |
|||
name, |
|||
stream, |
|||
overrideExisting, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.DeleteAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.ExistsAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetOrNullAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class BlobContainer : IBlobContainer |
|||
{ |
|||
protected string ContainerName { get; } |
|||
|
|||
protected BlobContainerConfiguration Configuration { get; } |
|||
|
|||
protected IBlobProvider Provider { get; } |
|||
|
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
|||
|
|||
public BlobContainer( |
|||
string containerName, |
|||
BlobContainerConfiguration configuration, |
|||
IBlobProvider provider, |
|||
ICurrentTenant currentTenant, |
|||
ICancellationTokenProvider cancellationTokenProvider) |
|||
{ |
|||
ContainerName = containerName; |
|||
Configuration = configuration; |
|||
Provider = provider; |
|||
CurrentTenant = currentTenant; |
|||
CancellationTokenProvider = cancellationTokenProvider; |
|||
} |
|||
|
|||
public virtual Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.SaveAsync( |
|||
new BlobProviderSaveArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
stream, |
|||
overrideExisting, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.DeleteAsync( |
|||
new BlobProviderDeleteArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.ExistsAsync( |
|||
new BlobProviderExistsArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual async Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var stream = await Provider.GetOrNullAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
|
|||
if (stream == null) |
|||
{ |
|||
//TODO: Consider to throw some type of "not found" exception and handle on the HTTP status side
|
|||
throw new AbpException($"Could not found the requested BLOB '{name}' in the container '{ContainerName}'!"); |
|||
} |
|||
|
|||
return stream; |
|||
} |
|||
|
|||
public virtual Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.GetOrNullAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
protected virtual Guid? GetTenantIdOrNull() |
|||
{ |
|||
if (!Configuration.IsMultiTenant) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return CurrentTenant.Id; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainerConfiguration |
|||
{ |
|||
/// <summary>
|
|||
/// The provider to be used to store BLOBs of this container.
|
|||
/// </summary>
|
|||
public Type ProviderType { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Indicates whether this container is multi-tenant or not.
|
|||
///
|
|||
/// If this is <code>false</code> and your application is multi-tenant,
|
|||
/// then the container is shared by all tenants in the system.
|
|||
///
|
|||
/// This can be <code>true</code> even if your application is not multi-tenant.
|
|||
///
|
|||
/// Default: true.
|
|||
/// </summary>
|
|||
public bool IsMultiTenant { get; set; } = true; |
|||
|
|||
[NotNull] private readonly Dictionary<string, object> _properties; |
|||
|
|||
[CanBeNull] private readonly BlobContainerConfiguration _fallbackConfiguration; |
|||
|
|||
public BlobContainerConfiguration(BlobContainerConfiguration fallbackConfiguration = null) |
|||
{ |
|||
_fallbackConfiguration = fallbackConfiguration; |
|||
_properties = new Dictionary<string, object>(); |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public T GetConfigurationOrDefault<T>(string name, T defaultValue = default) |
|||
{ |
|||
return (T) GetConfigurationOrNull(name, defaultValue); |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public object GetConfigurationOrNull(string name, object defaultValue = null) |
|||
{ |
|||
return _properties.GetOrDefault(name) ?? |
|||
_fallbackConfiguration?.GetConfigurationOrNull(name, defaultValue) ?? |
|||
defaultValue; |
|||
} |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration SetConfiguration([NotNull] string name, [CanBeNull] object value) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
Check.NotNull(value, nameof(value)); |
|||
|
|||
_properties[name] = value; |
|||
|
|||
return this; |
|||
} |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration ClearConfiguration([NotNull] string name) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
_properties.Remove(name); |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobContainerConfigurationExtensions |
|||
{ |
|||
public static T GetConfiguration<T>( |
|||
[NotNull] this BlobContainerConfiguration containerConfiguration, |
|||
[NotNull] string name) |
|||
{ |
|||
return (T) containerConfiguration.GetConfiguration(name); |
|||
} |
|||
|
|||
public static object GetConfiguration( |
|||
[NotNull] this BlobContainerConfiguration containerConfiguration, |
|||
[NotNull] string name) |
|||
{ |
|||
var value = containerConfiguration.GetConfigurationOrNull(name); |
|||
if (value == null) |
|||
{ |
|||
throw new AbpException($"Could not find the configuration value for '{name}'!"); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobContainerConfigurationProviderExtensions |
|||
{ |
|||
public static BlobContainerConfiguration Get<TContainer>( |
|||
this IBlobContainerConfigurationProvider configurationProvider) |
|||
{ |
|||
return configurationProvider.Get(BlobContainerNameAttribute.GetContainerName<TContainer>()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainerConfigurations |
|||
{ |
|||
private BlobContainerConfiguration Default => GetConfiguration<DefaultContainer>(); |
|||
|
|||
private readonly Dictionary<string, BlobContainerConfiguration> _containers; |
|||
|
|||
public BlobContainerConfigurations() |
|||
{ |
|||
_containers = new Dictionary<string, BlobContainerConfiguration> |
|||
{ |
|||
//Add default container
|
|||
[BlobContainerNameAttribute.GetContainerName<DefaultContainer>()] = new BlobContainerConfiguration() |
|||
}; |
|||
} |
|||
|
|||
public BlobContainerConfigurations Configure<TContainer>( |
|||
Action<BlobContainerConfiguration> configureAction) |
|||
{ |
|||
return Configure( |
|||
BlobContainerNameAttribute.GetContainerName<TContainer>(), |
|||
configureAction |
|||
); |
|||
} |
|||
|
|||
public BlobContainerConfigurations Configure( |
|||
[NotNull] string name, |
|||
[NotNull] Action<BlobContainerConfiguration> configureAction) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
Check.NotNull(configureAction, nameof(configureAction)); |
|||
|
|||
configureAction( |
|||
_containers.GetOrAdd( |
|||
name, |
|||
() => new BlobContainerConfiguration(Default) |
|||
) |
|||
); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public BlobContainerConfigurations ConfigureDefault(Action<BlobContainerConfiguration> configureAction) |
|||
{ |
|||
configureAction(Default); |
|||
return this; |
|||
} |
|||
|
|||
public BlobContainerConfigurations ConfigureAll(Action<string, BlobContainerConfiguration> configureAction) |
|||
{ |
|||
foreach (var container in _containers) |
|||
{ |
|||
configureAction(container.Key, container.Value); |
|||
} |
|||
|
|||
return this; |
|||
} |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration GetConfiguration<TContainer>() |
|||
{ |
|||
return GetConfiguration(BlobContainerNameAttribute.GetContainerName<TContainer>()); |
|||
} |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration GetConfiguration([NotNull] string name) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
return _containers.GetOrDefault(name) ?? |
|||
Default; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobContainerExtensions |
|||
{ |
|||
public static async Task SaveAsync( |
|||
this IBlobContainer container, |
|||
string name, |
|||
byte[] bytes, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default |
|||
) |
|||
{ |
|||
using (var memoryStream = new MemoryStream(bytes)) |
|||
{ |
|||
await container.SaveAsync( |
|||
name, |
|||
memoryStream, |
|||
overrideExisting, |
|||
cancellationToken |
|||
); |
|||
} |
|||
} |
|||
|
|||
public static async Task<byte[]> GetAllBytesAsync( |
|||
this IBlobContainer container, |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
using (var stream = await container.GetAsync(name, cancellationToken)) |
|||
{ |
|||
return await stream.GetAllBytesAsync(cancellationToken); |
|||
} |
|||
} |
|||
|
|||
public static async Task<byte[]> GetAllBytesOrNullAsync( |
|||
this IBlobContainer container, |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
var stream = await container.GetOrNullAsync(name, cancellationToken); |
|||
if (stream == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
using (stream) |
|||
{ |
|||
return await stream.GetAllBytesAsync(cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System.Threading; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainerFactory : IBlobContainerFactory, ITransientDependency |
|||
{ |
|||
protected IBlobProviderSelector ProviderSelector { get; } |
|||
|
|||
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } |
|||
|
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
|||
|
|||
public BlobContainerFactory( |
|||
IBlobContainerConfigurationProvider configurationProvider, |
|||
ICurrentTenant currentTenant, |
|||
ICancellationTokenProvider cancellationTokenProvider, |
|||
IBlobProviderSelector providerSelector) |
|||
{ |
|||
ConfigurationProvider = configurationProvider; |
|||
CurrentTenant = currentTenant; |
|||
CancellationTokenProvider = cancellationTokenProvider; |
|||
ProviderSelector = providerSelector; |
|||
} |
|||
|
|||
public virtual IBlobContainer Create(string name, CancellationToken cancellationToken = default) |
|||
{ |
|||
var configuration = ConfigurationProvider.Get(name); |
|||
|
|||
return new BlobContainer( |
|||
name, |
|||
configuration, |
|||
ProviderSelector.Get(name), |
|||
CurrentTenant, |
|||
CancellationTokenProvider |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobContainerFactoryExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a named container.
|
|||
/// </summary>
|
|||
/// <param name="blobContainerFactory">The blob container manager</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
/// <returns>
|
|||
/// The container object.
|
|||
/// </returns>
|
|||
public static IBlobContainer Create<TContainer>( |
|||
this IBlobContainerFactory blobContainerFactory, |
|||
CancellationToken cancellationToken = default |
|||
) |
|||
{ |
|||
return blobContainerFactory.Create( |
|||
BlobContainerNameAttribute.GetContainerName<TContainer>(), |
|||
cancellationToken |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainerNameAttribute : Attribute |
|||
{ |
|||
[NotNull] |
|||
public string Name { get; } |
|||
|
|||
public BlobContainerNameAttribute([NotNull] string name) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
Name = name; |
|||
} |
|||
|
|||
public virtual string GetName(Type type) |
|||
{ |
|||
return Name; |
|||
} |
|||
|
|||
public static string GetContainerName<T>() |
|||
{ |
|||
return GetContainerName(typeof(T)); |
|||
} |
|||
|
|||
public static string GetContainerName(Type type) |
|||
{ |
|||
var nameAttribute = type.GetCustomAttribute<BlobContainerNameAttribute>(); |
|||
|
|||
if (nameAttribute == null) |
|||
{ |
|||
return type.FullName; |
|||
} |
|||
|
|||
return nameAttribute.GetName(type); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public abstract class BlobProviderArgs |
|||
{ |
|||
[NotNull] |
|||
public string ContainerName { get; } |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration Configuration { get; } |
|||
|
|||
[NotNull] |
|||
public string BlobName { get; } |
|||
|
|||
public CancellationToken CancellationToken { get; } |
|||
|
|||
public Guid? TenantId { get; } |
|||
|
|||
protected BlobProviderArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
ContainerName = Check.NotNullOrWhiteSpace(containerName, nameof(containerName)); |
|||
Configuration = Check.NotNull(configuration, nameof(configuration)); |
|||
BlobName = Check.NotNullOrWhiteSpace(blobName, nameof(blobName)); |
|||
TenantId = tenantId; |
|||
CancellationToken = cancellationToken; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public abstract class BlobProviderBase : IBlobProvider |
|||
{ |
|||
public abstract Task SaveAsync(BlobProviderSaveArgs args); |
|||
|
|||
public abstract Task<bool> DeleteAsync(BlobProviderDeleteArgs args); |
|||
|
|||
public abstract Task<bool> ExistsAsync(BlobProviderExistsArgs args); |
|||
|
|||
public abstract Task<Stream> GetOrNullAsync(BlobProviderGetArgs args); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobProviderDeleteArgs : BlobProviderArgs |
|||
{ |
|||
public BlobProviderDeleteArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
: base( |
|||
containerName, |
|||
configuration, |
|||
blobName, |
|||
tenantId, |
|||
cancellationToken) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobProviderExistsArgs : BlobProviderArgs |
|||
{ |
|||
public BlobProviderExistsArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
: base( |
|||
containerName, |
|||
configuration, |
|||
blobName, |
|||
tenantId, |
|||
cancellationToken) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobProviderGetArgs : BlobProviderArgs |
|||
{ |
|||
public BlobProviderGetArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
: base( |
|||
containerName, |
|||
configuration, |
|||
blobName, |
|||
tenantId, |
|||
cancellationToken) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobProviderSaveArgs : BlobProviderArgs |
|||
{ |
|||
[NotNull] |
|||
public Stream BlobStream { get; } |
|||
|
|||
public bool OverrideExisting { get; } |
|||
|
|||
public BlobProviderSaveArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[NotNull] Stream blobStream, |
|||
bool overrideExisting = false, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
: base( |
|||
containerName, |
|||
configuration, |
|||
blobName, |
|||
tenantId, |
|||
cancellationToken) |
|||
{ |
|||
BlobStream = Check.NotNull(blobStream, nameof(blobStream)); |
|||
OverrideExisting = overrideExisting; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobProviderSelectorExtensions |
|||
{ |
|||
public static IBlobProvider Get<TContainer>( |
|||
[NotNull] this IBlobProviderSelector selector) |
|||
{ |
|||
Check.NotNull(selector, nameof(selector)); |
|||
|
|||
return selector.Get(BlobContainerNameAttribute.GetContainerName<TContainer>()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class DefaultBlobContainerConfigurationProvider : IBlobContainerConfigurationProvider, ITransientDependency |
|||
{ |
|||
protected AbpBlobStoringOptions Options { get; } |
|||
|
|||
public DefaultBlobContainerConfigurationProvider(IOptions<AbpBlobStoringOptions> options) |
|||
{ |
|||
Options = options.Value; |
|||
} |
|||
|
|||
public virtual BlobContainerConfiguration Get(string name) |
|||
{ |
|||
return Options.Containers.GetConfiguration(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.DynamicProxy; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class DefaultBlobProviderSelector : IBlobProviderSelector, ITransientDependency |
|||
{ |
|||
protected IEnumerable<IBlobProvider> BlobProviders { get; } |
|||
|
|||
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } |
|||
|
|||
public DefaultBlobProviderSelector( |
|||
IBlobContainerConfigurationProvider configurationProvider, |
|||
IEnumerable<IBlobProvider> blobProviders) |
|||
{ |
|||
ConfigurationProvider = configurationProvider; |
|||
BlobProviders = blobProviders; |
|||
} |
|||
|
|||
[NotNull] |
|||
public virtual IBlobProvider Get([NotNull] string containerName) |
|||
{ |
|||
Check.NotNull(containerName, nameof(containerName)); |
|||
|
|||
var configuration = ConfigurationProvider.Get(containerName); |
|||
|
|||
if (!BlobProviders.Any()) |
|||
{ |
|||
throw new AbpException("No BLOB Storage provider was registered! At least one provider must be registered to be able to use the Blog Storing System."); |
|||
} |
|||
|
|||
foreach (var provider in BlobProviders) |
|||
{ |
|||
if (ProxyHelper.GetUnProxiedType(provider).IsAssignableTo(configuration.ProviderType)) |
|||
{ |
|||
return provider; |
|||
} |
|||
} |
|||
|
|||
throw new AbpException( |
|||
$"Could not find the BLOB Storage provider with the type ({configuration.ProviderType.AssemblyQualifiedName}) configured for the container {containerName} and no default provider was set." |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
[BlobContainerName("Default")] |
|||
public class DefaultContainer |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobContainer<TContainer> : IBlobContainer |
|||
where TContainer: class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public interface IBlobContainer |
|||
{ |
|||
/// <summary>
|
|||
/// Saves a blob <see cref="Stream"/> to the container.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the blob</param>
|
|||
/// <param name="stream">A stream for the blob</param>
|
|||
/// <param name="overrideExisting">
|
|||
/// Set <code>true</code> to override if there is already a blob in the container with the given name.
|
|||
/// If set to <code>false</code> (default), throws exception if there is already a blob in the container with the given name.
|
|||
/// </param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
/// <summary>
|
|||
/// Deletes a blob from the container.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the blob</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
/// <returns>
|
|||
/// Returns true if actually deleted the blob.
|
|||
/// Returns false if the blob with the given <paramref name="name"/> was not exists.
|
|||
/// </returns>
|
|||
Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
/// <summary>
|
|||
/// Checks if a blob does exists in the container.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the blob</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
/// <summary>
|
|||
/// Gets a blob from the container.
|
|||
/// It actually gets a <see cref="Stream"/> to read the blob data.
|
|||
/// It throws exception if there is no blob with the given <paramref name="name"/>.
|
|||
/// Use <see cref="GetOrNullAsync"/> if you want to get <code>null</code> if there is no blob with the given <paramref name="name"/>.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the blob</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
/// <returns>
|
|||
/// A <see cref="Stream"/> to read the blob data.
|
|||
/// </returns>
|
|||
Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
/// <summary>
|
|||
/// Gets a blob from the container, or returns null if there is no blob with the given <paramref name="name"/>.
|
|||
/// It actually gets a <see cref="Stream"/> to read the blob data.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the blob</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
/// <returns>
|
|||
/// A <see cref="Stream"/> to read the blob data.
|
|||
/// </returns>
|
|||
Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
//TODO: Create shortcut extension methods: GetAsArraryAsync, GetAsStringAsync(encoding) (and null versions)
|
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobContainerConfigurationProvider |
|||
{ |
|||
BlobContainerConfiguration Get(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobContainerFactory |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a named container.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the container</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
/// <returns>
|
|||
/// The container object.
|
|||
/// </returns>
|
|||
IBlobContainer Create( |
|||
string name, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobProvider |
|||
{ |
|||
Task SaveAsync(BlobProviderSaveArgs args); |
|||
|
|||
Task<bool> DeleteAsync(BlobProviderDeleteArgs args); |
|||
|
|||
Task<bool> ExistsAsync(BlobProviderExistsArgs args); |
|||
|
|||
Task<Stream> GetOrNullAsync(BlobProviderGetArgs args); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobProviderSelector |
|||
{ |
|||
[NotNull] |
|||
IBlobProvider Get([NotNull] string containerName); |
|||
} |
|||
} |
|||
@ -0,0 +1,444 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json; |
|||
using Newtonsoft.Json.Linq; |
|||
using Volo.Abp.Cli.Args; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands |
|||
{ |
|||
public class TranslateCommand: IConsoleCommand, ITransientDependency |
|||
{ |
|||
public ILogger<TranslateCommand> Logger { get; set; } |
|||
|
|||
public Task ExecuteAsync(CommandLineArgs commandLineArgs) |
|||
{ |
|||
var currentDirectory = Directory.GetCurrentDirectory(); |
|||
|
|||
var apply = commandLineArgs.Options.ContainsKey(Options.Apply.Short) || commandLineArgs.Options.ContainsKey(Options.Apply.Long); |
|||
if (apply) |
|||
{ |
|||
var inputFile = Path.Combine(currentDirectory, |
|||
commandLineArgs.Options.GetOrNull(Options.File.Short, Options.File.Long) |
|||
?? "abp-translation.json"); |
|||
|
|||
Logger.LogInformation("Abp translate apply..."); |
|||
Logger.LogInformation("Input file: " + inputFile); |
|||
|
|||
ApplyAbpTranslateInfo(currentDirectory, inputFile); |
|||
} |
|||
else |
|||
{ |
|||
var targetCulture = commandLineArgs.Options.GetOrNull(Options.Culture.Short, Options.Culture.Long); |
|||
if (targetCulture == null) |
|||
{ |
|||
throw new CliUsageException( |
|||
"Target culture is missing!" + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
var referenceCulture = commandLineArgs.Options.GetOrNull(Options.ReferenceCulture.Short, Options.ReferenceCulture.Long) |
|||
?? "en"; |
|||
|
|||
var outputFile = Path.Combine(currentDirectory, |
|||
commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long) |
|||
?? "abp-translation.json"); |
|||
|
|||
var allValues = commandLineArgs.Options.ContainsKey(Options.AllValues.Short) || |
|||
commandLineArgs.Options.ContainsKey(Options.AllValues.Long); |
|||
|
|||
Logger.LogInformation("Abp translate..."); |
|||
Logger.LogInformation("Target culture: " + targetCulture); |
|||
Logger.LogInformation("Reference culture: " + referenceCulture); |
|||
Logger.LogInformation("Output file: " + outputFile); |
|||
|
|||
if (allValues) |
|||
{ |
|||
Logger.LogInformation("Include all keys"); |
|||
} |
|||
|
|||
var translateInfo = GetAbpTranslateInfo(currentDirectory, targetCulture, referenceCulture, allValues); |
|||
|
|||
File.WriteAllText(outputFile, JsonConvert.SerializeObject(translateInfo, Formatting.Indented)); |
|||
|
|||
Logger.LogInformation($"The translation file has been created."); |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
private AbpTranslateInfo GetAbpTranslateInfo(string directory, string targetCultureName, string referenceCultureName, bool allValues) |
|||
{ |
|||
var translateInfo = new AbpTranslateInfo |
|||
{ |
|||
ReferenceCulture = referenceCultureName, |
|||
TargetCulture = targetCultureName, |
|||
Resources = new List<AbpTranslateResource>() |
|||
}; |
|||
|
|||
var referenceCultureFiles = GetCultureJsonFiles(directory, referenceCultureName); |
|||
foreach (var filePath in referenceCultureFiles) |
|||
{ |
|||
var directoryName = Path.GetDirectoryName(filePath) ?? string.Empty; |
|||
|
|||
var referenceLocalizationInfo = GetAbpLocalizationInfoOrNull(filePath); |
|||
if (referenceLocalizationInfo == null) // Not abp json file
|
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var resource = new AbpTranslateResource |
|||
{ |
|||
ResourcePath = directoryName, |
|||
Texts = new List<AbpTranslateResourceText>() |
|||
}; |
|||
|
|||
foreach (var text in referenceLocalizationInfo.Texts) |
|||
{ |
|||
resource.Texts.Add(new AbpTranslateResourceText |
|||
{ |
|||
LocalizationKey = text.Name, |
|||
Reference = text.Value, |
|||
Target = string.Empty |
|||
}); |
|||
} |
|||
|
|||
//Use target json file content to fill resource texts
|
|||
var targetFile = Path.Combine(directoryName, $"{targetCultureName}.json"); |
|||
if (File.Exists(targetFile)) |
|||
{ |
|||
var targetLocalizationInfo = GetAbpLocalizationInfoOrNull(targetFile); |
|||
foreach (var referenceResourceText in resource.Texts) |
|||
{ |
|||
var text = targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == referenceResourceText.LocalizationKey); |
|||
referenceResourceText.Target = text?.Value ?? string.Empty; |
|||
} |
|||
} |
|||
|
|||
if (!allValues) |
|||
{ |
|||
//Only include missing keys.
|
|||
resource.Texts.RemoveAll(x => !x.Target.Equals(string.Empty)); |
|||
} |
|||
|
|||
if (resource.Texts.Any()) |
|||
{ |
|||
translateInfo.Resources.Add(resource); |
|||
} |
|||
} |
|||
|
|||
return translateInfo; |
|||
} |
|||
|
|||
private void ApplyAbpTranslateInfo(string directory, string filename) |
|||
{ |
|||
var translateJsonPath = Path.Combine(directory, filename); |
|||
if (!File.Exists(translateJsonPath)) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"{translateJsonPath} file does not exist.." + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
var translateInfo = GetAbpTranslateInfo(translateJsonPath); |
|||
foreach (var resource in translateInfo.Resources) |
|||
{ |
|||
var targetFile = Path.Combine(resource.ResourcePath, translateInfo.TargetCulture + ".json"); |
|||
var targetLocalizationInfo = File.Exists(targetFile) |
|||
? GetAbpLocalizationInfoOrNull(targetFile) |
|||
: new AbpLocalizationInfo() |
|||
{ |
|||
Culture = translateInfo.TargetCulture, |
|||
Texts = new List<NameValue>() |
|||
}; |
|||
|
|||
if (targetLocalizationInfo == null) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"Failed to get localization information from {targetFile} file." + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
var referenceFile = Path.Combine(resource.ResourcePath, translateInfo.ReferenceCulture + ".json"); |
|||
if (!File.Exists(referenceFile)) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"{referenceFile} file does not exist.." + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
var referenceLocalizationInfo = GetAbpLocalizationInfoOrNull(referenceFile); |
|||
if (referenceLocalizationInfo == null) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"Failed to get localization information from {referenceFile} file." + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
foreach (var text in resource.Texts) |
|||
{ |
|||
var targetText = targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == text.LocalizationKey); |
|||
if (targetText != null) |
|||
{ |
|||
Logger.LogInformation($"Update translation: {targetText.Name} => " + text.Target); |
|||
targetText.Value = text.Target; |
|||
} |
|||
else |
|||
{ |
|||
Logger.LogInformation($"Create translation: {text.LocalizationKey} => " + text.Target); |
|||
targetLocalizationInfo.Texts.Add(new NameValue(text.LocalizationKey, text.Target)); |
|||
} |
|||
} |
|||
|
|||
Logger.LogInformation($"Write translation json to {targetFile}."); |
|||
|
|||
// sort keys
|
|||
targetLocalizationInfo = SortLocalizedKeys(targetLocalizationInfo, referenceLocalizationInfo); |
|||
File.WriteAllText(targetFile, AbpLocalizationInfoToJsonFile(targetLocalizationInfo)); |
|||
|
|||
// remove translate json file(abp-translation.json)
|
|||
File.Delete(translateJsonPath); |
|||
Logger.LogInformation($"Delete the {translateJsonPath} file, if you need to translate again, please re-run the [abp translate] command."); |
|||
} |
|||
} |
|||
|
|||
private static IEnumerable<string> GetCultureJsonFiles(string path,string cultureName) |
|||
{ |
|||
var excludeDirectory = new List<string>() |
|||
{ |
|||
"node_modules", |
|||
Path.Combine("bin", "debug"), |
|||
Path.Combine("obj", "debug") |
|||
}; |
|||
|
|||
var allCultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures); |
|||
|
|||
return Directory.GetFiles(path, "*.json", SearchOption.AllDirectories) |
|||
.Where(file => excludeDirectory.All(x => file.IndexOf(x, StringComparison.OrdinalIgnoreCase) == -1)) |
|||
.Where(jsonFile => allCultureInfos.Any(culture => jsonFile.EndsWith($"{cultureName}.json", StringComparison.OrdinalIgnoreCase))); |
|||
} |
|||
|
|||
private AbpLocalizationInfo GetAbpLocalizationInfoOrNull(string path) |
|||
{ |
|||
if (!File.Exists(path)) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"File {path} does not exist!" + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
var json = File.ReadAllText(path); |
|||
JObject jObject; |
|||
try |
|||
{ |
|||
jObject = JObject.Parse(json); |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var culture = jObject.GetValue("culture"); |
|||
var texts = jObject.GetValue("texts"); |
|||
if (culture == null || texts == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var localizationInfo = new AbpLocalizationInfo |
|||
{ |
|||
Culture = culture.Value<string>(), |
|||
Texts = new List<NameValue>() |
|||
}; |
|||
|
|||
foreach (var text in texts) |
|||
{ |
|||
var property = (text as JProperty); |
|||
localizationInfo.Texts.Add(new NameValue(property?.Name, property?.Value.Value<string>())); |
|||
} |
|||
|
|||
return localizationInfo; |
|||
} |
|||
|
|||
private static string AbpLocalizationInfoToJsonFile(AbpLocalizationInfo localizationInfo) |
|||
{ |
|||
var jObject = new JObject {{"culture", localizationInfo.Culture}}; |
|||
var value = new JObject(); |
|||
foreach (var text in localizationInfo.Texts) |
|||
{ |
|||
value.Add(text.Name, text.Value); |
|||
} |
|||
jObject.Add("texts", value); |
|||
return jObject.ToString(); |
|||
} |
|||
|
|||
private AbpTranslateInfo GetAbpTranslateInfo(string path) |
|||
{ |
|||
if (!File.Exists(path)) |
|||
{ |
|||
throw new CliUsageException( |
|||
$"File {path} does not exist!" + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
AbpTranslateInfo translateInfo; |
|||
try |
|||
{ |
|||
translateInfo = JsonConvert.DeserializeObject<AbpTranslateInfo>(File.ReadAllText(path)); |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
throw new CliUsageException( |
|||
e.Message + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
return translateInfo; |
|||
} |
|||
|
|||
private static AbpLocalizationInfo SortLocalizedKeys(AbpLocalizationInfo targetLocalizationInfo, AbpLocalizationInfo referenceLocalizationInfo) |
|||
{ |
|||
var sortedLocalizationInfo = new AbpLocalizationInfo |
|||
{ |
|||
Culture = targetLocalizationInfo.Culture, |
|||
Texts = new List<NameValue>() |
|||
}; |
|||
|
|||
foreach (var targetText in referenceLocalizationInfo.Texts.Select(text => |
|||
targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == text.Name)) |
|||
.Where(targetText => targetText != null)) |
|||
{ |
|||
sortedLocalizationInfo.Texts.Add(targetText); |
|||
} |
|||
|
|||
return sortedLocalizationInfo; |
|||
} |
|||
|
|||
public string GetUsageInfo() |
|||
{ |
|||
var sb = new StringBuilder(); |
|||
|
|||
sb.AppendLine(""); |
|||
sb.AppendLine("Usage:"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine(" abp translate [options]"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("Options:"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("--culture|-c <culture> Target culture. eg: zh-Hans"); |
|||
sb.AppendLine("--reference-culture|-r <culture> Default: en"); |
|||
sb.AppendLine("--output|-o <file-name> Output file name, Default abp-translation.json"); |
|||
sb.AppendLine("--all-values|-all Include all keys. Default false"); |
|||
sb.AppendLine("--apply|-a Creates or updates the file for the translated culture."); |
|||
sb.AppendLine("--file|-f <file-name> Default: abp-translation.json"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("Examples:"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine(" abp translate -c zh-Hans"); |
|||
sb.AppendLine(" abp translate -c zh-Hans -r en -a"); |
|||
sb.AppendLine(" abp translate --apply"); |
|||
sb.AppendLine(" abp translate -a -f my-translation.json"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); |
|||
|
|||
return sb.ToString(); |
|||
} |
|||
|
|||
public string GetShortDescription() |
|||
{ |
|||
return "Mainly used to translate ABP's resources (JSON files) easier."; |
|||
} |
|||
|
|||
public static class Options |
|||
{ |
|||
public static class Culture |
|||
{ |
|||
public const string Short = "c"; |
|||
public const string Long = "culture"; |
|||
} |
|||
|
|||
public static class ReferenceCulture |
|||
{ |
|||
public const string Short = "r"; |
|||
public const string Long = "reference-culture"; |
|||
} |
|||
|
|||
public static class Output |
|||
{ |
|||
public const string Short = "o"; |
|||
public const string Long = "output"; |
|||
} |
|||
|
|||
public static class AllValues |
|||
{ |
|||
public const string Short = "all"; |
|||
public const string Long = "all-values"; |
|||
} |
|||
|
|||
public static class Apply |
|||
{ |
|||
public const string Short = "a"; |
|||
public const string Long = "apply"; |
|||
} |
|||
|
|||
public static class File |
|||
{ |
|||
public const string Short = "f"; |
|||
public const string Long = "file"; |
|||
} |
|||
} |
|||
|
|||
public class AbpTranslateInfo |
|||
{ |
|||
public string ReferenceCulture { get; set; } |
|||
|
|||
public string TargetCulture { get; set; } |
|||
|
|||
public List<AbpTranslateResource> Resources { get; set; } |
|||
} |
|||
|
|||
public class AbpTranslateResource |
|||
{ |
|||
public string ResourcePath { get; set; } |
|||
|
|||
public List<AbpTranslateResourceText> Texts { get; set; } |
|||
} |
|||
|
|||
public class AbpTranslateResourceText |
|||
{ |
|||
public string LocalizationKey { get; set; } |
|||
|
|||
public string Reference { get; set; } |
|||
|
|||
public string Target { get; set; } |
|||
} |
|||
|
|||
public class AbpLocalizationInfo |
|||
{ |
|||
public string Culture { get; set; } |
|||
|
|||
public List<NameValue> Texts { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace Volo.Abp |
|||
{ |
|||
public class AbpShutdownException : AbpException |
|||
{ |
|||
public AbpShutdownException() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public AbpShutdownException(string message) |
|||
: base(message) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public AbpShutdownException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public AbpShutdownException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace Microsoft.EntityFrameworkCore |
|||
{ |
|||
public static class AbpMySqlModelBuilderExtensions |
|||
{ |
|||
public static void UseMySQL( |
|||
this ModelBuilder modelBuilder) |
|||
{ |
|||
modelBuilder.SetDatabaseProvider(EfCoreDatabaseProvider.MySql); |
|||
} |
|||
} |
|||
} |
|||