Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into dev

pull/4164/head
Alper Ebicoglu 6 years ago
parent
commit
5cc18581ce
  1. 20
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  2. 2
      docs/en/Entity-Framework-Core-Oracle.md
  3. 31
      docs/zh-Hans/CLI.md
  4. 17
      docs/zh-Hans/Entity-Framework-Core-MySQL.md
  5. 73
      docs/zh-Hans/Entity-Framework-Core-Oracle.md
  6. 1
      docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md
  7. 2
      docs/zh-Hans/Getting-Started.md
  8. 12
      docs/zh-Hans/SignalR-Integration.md
  9. 46
      docs/zh-Hans/Tutorials/Part-1.md
  10. 26
      docs/zh-Hans/Tutorials/Part-2.md
  11. 474
      docs/zh-Hans/UI/Angular/Component-Replacement.md
  12. 62
      docs/zh-Hans/UI/Angular/Localization.md
  13. 13
      docs/zh-Hans/docs-nav.json
  14. BIN
      docs/zh-Hans/images/hello-template.png
  15. BIN
      docs/zh-Hans/images/multiple-file-template.png
  16. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelper.cs
  17. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs
  18. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
  19. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs
  20. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs
  21. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelper.cs
  22. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelper.cs
  23. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs
  24. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs
  25. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptBundleTagHelperService.cs
  26. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptTagHelperService.cs
  27. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleBundleTagHelperService.cs
  28. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleTagHelperService.cs
  29. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs
  30. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs
  31. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs
  32. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json
  33. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js
  34. 15
      framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/ViewFeatures/ViewContextExtensions.cs
  35. 6
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/cs.json
  36. 5
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json
  37. 51
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
  38. 6
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  39. 7
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs
  40. 2
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json
  41. 7
      framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/cs.json
  42. 2
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json
  43. 8
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json
  44. 2
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json
  45. 4
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/cs.json
  46. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json
  47. 2
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json
  48. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/cs.json
  49. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/cs.json
  50. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json
  51. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json
  52. 7
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/cs.json
  53. 3
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json
  54. 6
      modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
  55. 9
      modules/blob-storing-database/Volo.Abp.BlobStoring.Database.sln
  56. 21
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.sln
  57. 23
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobService.cs
  58. 32
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj
  59. 32
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppHostedService.cs
  60. 56
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppModule.cs
  61. 20
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContext.cs
  62. 29
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContextFactory.cs
  63. 26
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbSchemaMigrator.cs
  64. 9
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/IBlobStoringHostDbSchemaMigrator.cs
  65. 9
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/IBlobService.cs
  66. 97
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.Designer.cs
  67. 62
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.cs
  68. 108
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.Designer.cs
  69. 34
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.cs
  70. 106
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs
  71. 7
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ProfilePictureContainer.cs
  72. 51
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Program.cs
  73. 5
      modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json
  74. 4
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/cs.json
  75. 2
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/en.json
  76. 4
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs
  77. 2
      modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/cs.json
  78. 6
      modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/cs.json
  79. 7
      modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs
  80. 2
      modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json
  81. 9
      modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json
  82. 6
      modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs
  83. 6
      modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs
  84. 23
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json
  85. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json
  86. 9
      modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json
  87. 11
      modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs
  88. 8
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json
  89. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json
  90. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json
  91. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs
  92. 6
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json
  93. 5
      modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs
  94. 12
      modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/cs.json
  95. 2
      modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs
  96. 11
      nupkg/common.ps1
  97. 2
      samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/cs.json
  98. 3
      samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/cs.json
  99. 2
      samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/cs.json
  100. 8
      samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/ProductManagementMenuContributor.cs

20
docs/en/AspNet-Boilerplate-Migration-Guide.md

@ -216,9 +216,9 @@ However, it provides the following methods those can be used to query a single e
* `FindAsync(id)` returns the entity or null if not found.
* `GetAsync(id)` method returns the entity or throws an `EntityNotFoundException` (which causes HTTP 404 status code) if not found.
#### Sync vs Async
#### Sync vs Async
ABP Framework repository has no sync methods (like `Insert`). All the methods are async (like `InsertAsync`). So, if your application has sync repository method usages, convert them to async versions.
ABP Framework repository has no sync methods (like `Insert`). All the methods are async (like `InsertAsync`). So, if your application has sync repository method usages, convert them to async versions.
In general, ABP Framework forces you to completely use async everywhere, because mixing async & sync methods is not a recommended approach.
@ -444,7 +444,7 @@ ASP.NET Boilerplate uses Castle Windsor's [logging facility](http://docs.castlep
using Castle.Core.Logging; //1: Import Logging namespace
public class TaskAppService : ITaskAppService
{
{
//2: Getting a logger using property injection
public ILogger Logger { get; set; }
@ -693,26 +693,22 @@ public class AbpTenantManagementWebMainMenuContributor : IMenuContributor
var administrationMenu = context.Menu.GetAdministration();
//Resolve some needed services from the DI container
var authorizationService = context.ServiceProvider
.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider
.GetRequiredService<IStringLocalizer<AbpTenantManagementResource>>();
var l = context.GetLocalizer<AbpTenantManagementResource>();
var tenantManagementMenuItem = new ApplicationMenuItem(
TenantManagementMenuNames.GroupName,
l["Menu:TenantManagement"],
icon: "fa fa-users");
administrationMenu.AddItem(tenantManagementMenuItem);
//Conditionally add the "Tenants" menu item based on the permission
if (await authorizationService
.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
if (await context.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
{
tenantManagementMenuItem.AddItem(
new ApplicationMenuItem(
TenantManagementMenuNames.Tenants,
l["Tenants"],
l["Tenants"],
url: "/TenantManagement/Tenants"));
}
}
@ -731,4 +727,4 @@ The following features are not present for the ABP Framework. Here, a list of so
* [Real time notification system](https://aspnetboilerplate.com/Pages/Documents/Notification-System) ([#633](https://github.com/abpframework/abp/issues/633))
* [NHibernate Integration](https://aspnetboilerplate.com/Pages/Documents/NHibernate-Integration) ([#339](https://github.com/abpframework/abp/issues/339)) - We don't intent to work on this, but any community contribution welcome.
Some of these features will eventually be implemented. However, you can implement them yourself if they are important for you. If you want, you can [contribute](Contribution/Index.md) to the framework, it is appreciated.
Some of these features will eventually be implemented. However, you can implement them yourself if they are important for you. If you want, you can [contribute](Contribution/Index.md) to the framework, it is appreciated.

2
docs/en/Entity-Framework-Core-Oracle.md

@ -40,7 +40,7 @@ var builder = (DbContextOptionsBuilder<YourProjectNameMigrationsDbContext>)
## 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.
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.

31
docs/zh-Hans/CLI.md

@ -18,6 +18,37 @@ dotnet tool update -g Volo.Abp.Cli
## Commands
这里是所有可用的命令列表:
* **`help`**: 展示ABP CLI的用法帮助信息.
* **`new`**:生成基于ABP的[启动模板](Startup-Templates/Index.md).
* **`update`**:自动更新的ABP解决方案ABP相关的NuGet和NPM包.
* **`add-package`**: 添加ABP包到项目.
* **`add-module`**: 添加[应用模块](https://docs.abp.io/en/abp/latest/Modules/Index)到解决方案.
* **`generate-proxy`**: 生成客户端代理以使用服务器上的HTTP API端点.
* **`switch-to-preview`**: 切换解决方案所有ABP相关包为[夜间构建](Nightly-Builds.md)版本.
* **`switch-to-stable`**: 切换解决方案所有ABP相关包为最新的稳定版本.
* **`translate`**: 当源代码控制存储库中有多个JSON[本地化](Localization.md文件时,可简化翻译本地化文件的过程.
* **`login`**: 使用你在[abp.io](https://abp.io/)的用户名和密码在你的计算机上认证.
* **`logout`**: 在你的计算机注销认证.
### help
展示ABP CLI的基本用法:
用法:
````bash
abp help [command-name]
````
示例:
````bash
abp help # Shows a general help.
abp help new # Shows help about the "new" command.
````
### new
生成基于ABP[启动模板](Startup-Templates/Index.md)的新解决方案.

17
docs/zh-Hans/Entity-Framework-Core-MySQL.md

@ -25,23 +25,6 @@ MySQL连接字符串与SQL Server连接字符串不同. 所以检查你的解决
通常需要更改 `.DbMigrator``.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构.
## 更改迁移DbContext
MySQL DBMS与SQL Server有一些细微的差异. 某些模块数据库映射配置(尤其是字段长度)会导致MySQL出现问题. 例如某些[IdentityServer模块](Modules/IdentityServer.md)表就存在这样的问题,它提供了一个选项可以根据你的DBMS配置字段.
启动模板包含*YourProjectName*MigrationsDbContext,它负责维护和迁移数据库架构. 此DbContext基本上调用依赖模块的扩展方法来配置其数据库表.
打开 *YourProjectName*MigrationsDbContext 更改 `builder.ConfigureIdentityServer();` 行,如下所示:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
然后 `ConfigureIdentityServer()` 方法会将字段长度设置为不超过MySQL的限制. 如果在创建或执行数据库迁移时遇到任何问题请参考相关的模块文档.
## 重新生成迁移
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败.

73
docs/zh-Hans/Entity-Framework-Core-Oracle.md

@ -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` 项目创建数据库和初始种子数据.
## 运行应用程序
它已准备就绪, 只需要运行该应用程序与享受编码.

1
docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md

@ -6,6 +6,7 @@ ABP框架为一些常见的DMBS提供了简化配置的**集成包**,你可以
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
* [Oracle](Entity-Framework-Core-Oracle.md)
* [SQLite](Entity-Framework-Core-SQLite.md)
你也可以不使用集成包配置DBMS提供程序,虽然总是建议使用集成包(它也使不同模块之间的依赖版本成为标准版本),但是如果没有用于DBMS提供程序的集成包,也可以手动集成.

2
docs/zh-Hans/Getting-Started.md

@ -403,7 +403,7 @@ yarn start
在上面的管理界面中,可以通过使用[Expo Client](https://expo.io/tools#client)扫描二维码,使用Android模拟器,iOS模拟器或真机来启动应用程序.
> 请参阅[expo.io](https://docs.expo.io/versions/v36.0.0/workflow/ios-simulator/)上的[Android Studio模拟器](https://docs.expo.io/versions/v36.0.0/workflow/android-studio-emulator/)和[iOS模拟器文档](https://docs.expo.io/versions/v36.0.0/workflow/android-studio-emulator/).
> 请参阅expo.io上的[Android Studio模拟器](https://docs.expo.io/workflow/android-simulator/)和[iOS模拟器文档](https://docs.expo.io/workflow/ios-simulator/).
![React Native login screen on iPhone 11](images/rn-login-iphone.png)

12
docs/zh-Hans/SignalR-Integration.md

@ -224,4 +224,14 @@ ABP实现 `SignalR` 的 `IUserIdProvider` 接口,从ABP框架的 `ICurrentUser`
参阅 [SignalR集成Demo](https://github.com/abpframework/abp-samples/tree/master/SignalRDemo),它有一个简单的聊天页面,可以在(经过身份验证的)用户之间发送消息.
![signalr-demo-chat](images/signalr-demo-chat.png)
![signalr-demo-chat](images/signalr-demo-chat.png)
## 备注
ABP框架不会更改SignalR. 就像在其他ASP.NET Core应用程序中一样,它也可以在基于ABP框架的应用程序中工作.
参考[微软文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/scale)托管和扩展您的应用程序,集成[Azure](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/publish-to-azure-web-app)或[Redis底版](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/redis-backplane)...等.
## 另请参阅
* [微软SignalR文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction)

46
docs/zh-Hans/Tutorials/Part-1.md

@ -30,7 +30,7 @@ ASP.NET Core {{UI_Value}} 系列教程包括三个3个部分:
- [Part-2: 创建,编辑,删除书籍](Part-2.md)
- [Part-3: 集成测试](Part-3.md)
> 你也可以观看由ABP社区成员为本教程录制的[视频课程](https://amazingsolutions.teachable.com/p/lets-build-the-booktore-application).
> 你也可以观看由ABP社区成员为本教程录制的[视频课程](https://amazingsolutions.teachable.com/p/lets-build-the-bookstore-application).
### 创建新项目
@ -44,19 +44,19 @@ ASP.NET Core {{UI_Value}} 系列教程包括三个3个部分:
abp new Acme.BookStore --template app --database-provider {{DB}} --ui {{UI_Text}} --mobile none
```
![Creating project](./images/booktore-create-project-{{UI_Text}}.png)
![Creating project](./images/bookstore-create-project-{{UI_Text}}.png)
### 应用迁移
项目创建后,需要应用初始化迁移创建数据库. 运行 `Acme.BookStore.DbMigrator` 应用程序. 它会应用所有迁移,完成流程后你会看到以下结果,数据库已经准备好了!
![Migrations applied](./images/booktore-migrations-applied-{{UI_Text}}.png)
![Migrations applied](./images/bookstore-migrations-applied-{{UI_Text}}.png)
> 另外你也可以在 Visual Studio 包管理控制台运行 `Update-Database` 命令应用迁移.
#### 初始化数据库表
![Initial database tables](./images/booktore-database-tables-{{DB}}.png)
![Initial database tables](./images/bookstore-database-tables-{{DB}}.png)
### 运行应用程序
@ -64,7 +64,7 @@ abp new Acme.BookStore --template app --database-provider {{DB}} --ui {{UI_Text}
更多信息,参阅[入门教程](../../Getting-Started?UI={{UI}})的运行应用程序部分.
![Set as startup project](./images/booktore-start-project-{{UI_Text}}.png)
![Set as startup project](./images/bookstore-start-project-{{UI_Text}}.png)
{{if UI == "NG"}}
@ -105,7 +105,7 @@ http://localhost:4200/
下面的图片展示了从启动模板创建的项目是如何分层的.
![booktore-visual-studio-solution](./images/booktore-solution-structure-{{UI_Text}}.png)
![bookstore-visual-studio-solution](./images/bookstore-solution-structure-{{UI_Text}}.png)
> 你可以查看[应用程序模板文档](../startup-templates/application#solution-structure)以详细了解解决方案结构.
@ -295,7 +295,7 @@ namespace Acme.BookStore
这个启动模板使用了[EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)来创建并维护数据库结构.打开 **程序包管理器控制台(Package Manager Console) (PMC)** (工具/Nuget包管理器菜单)
![Open Package Manager Console](./images/booktore-open-package-manager-console.png)
![Open Package Manager Console](./images/bookstore-open-package-manager-console.png)
选择 `Acme.BookStore.EntityFrameworkCore.DbMigrations`作为默认的项目然后执行下面的命令:
@ -303,7 +303,7 @@ namespace Acme.BookStore
Add-Migration "Created_Book_Entity"
```
![booktore-pmc-add-book-migration](./images/booktore-pmc-add-book-migration-v2.png)
![bookstore-pmc-add-book-migration](./images/bookstore-pmc-add-book-migration-v2.png)
这样就会在 `Migrations` 文件夹中创建一个新的migration类.然后执行 `Update-Database` 命令更新数据库结构:
@ -311,7 +311,7 @@ Add-Migration "Created_Book_Entity"
Update-Database
````
![booktore-update-database-after-book-entity](./images/booktore-update-database-after-book-entity.png)
![bookstore-update-database-after-book-entity](./images/bookstore-update-database-after-book-entity.png)
#### 添加示例数据
@ -328,7 +328,7 @@ INSERT INTO AppBook (Id,CreationTime,[Name],[Type],PublishDate,Price) VALUES
('4fa024a1-95ac-49c6-a709-6af9e4d54b54', '2018-07-02', 'Pet Sematary',5,'1983-11-14','23.7')
```
![booktore-book-table](./images/booktore-book-table.png)
![bookstore-book-table](./images/bookstore-book-table.png)
{{end}}
@ -501,7 +501,7 @@ namespace Acme.BookStore
你会看到一些内置的接口和`Book`的接口,它们都是REST风格的:
![booktore-swagger](images/booktore-swagger.png)
![bookstore-swagger](images/bookstore-swagger.png)
Swagger有一个很好的UI来测试API. 你可以尝试执行`[GET] /api/app/book` API来获取书籍列表.
@ -529,11 +529,11 @@ acme.bookStore.book.getList({}).done(function (result) { console.log(result); })
运行这段代码会产生下面的输出:
![booktore-test-js-proxy-getlist](./images/booktore-test-js-proxy-getlist.png)
![bookstore-test-js-proxy-getlist](./images/bookstore-test-js-proxy-getlist.png)
你可以看到服务器返回的 **book list**.你还可以切换到开发者工具的 **network** 查看客户端到服务器端的通讯信息:
![booktore-test-js-proxy-getlist-network](./images/booktore-test-js-proxy-getlist-network.png)
![bookstore-test-js-proxy-getlist-network](./images/bookstore-test-js-proxy-getlist-network.png)
我们使用`create`方法 **创建一本新书**:
@ -555,7 +555,7 @@ successfully created the book with id: 439b0ea8-923e-8e1e-5d97-39f2c7ac4246
`Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Book`并添加一个名为`Index.cshtml`的Razor Page.
![booktore-add-index-page](./images/booktore-add-index-page-v2.png)
![bookstore-add-index-page](./images/bookstore-add-index-page-v2.png)
打开`Index.cshtml`并把内容修改成下面这样:
@ -621,7 +621,7 @@ namespace Acme.BookStore.Web.Menus
本地化文本位于`Acme.BookStore.Domain.Shared`项目的`Localization/BookStore`文件夹下:
![booktore-localization-files](./images/booktore-localization-files-v2.png)
![bookstore-localization-files](./images/bookstore-localization-files-v2.png)
打开`en.json`文件,将`Menu:BookStore`和`Menu:Book`键的本地化文本添加到文件末尾:
@ -653,7 +653,7 @@ namespace Acme.BookStore.Web.Menus
运行该应用程序,看到新菜单项已添加到顶部栏:
![booktore-menu-items](./images/booktore-new-menu-item.png)
![bookstore-menu-items](./images/bookstore-new-menu-item.png)
点击BookStore下Book子菜单项就会跳转到新增的书籍页面.
@ -701,7 +701,7 @@ namespace Acme.BookStore.Web.Menus
在`Pages/Book/`文件夹中创建 `index.js`文件
![booktore-index-js-file](./images/booktore-index-js-file-v2.png)
![bookstore-index-js-file](./images/bookstore-index-js-file-v2.png)
`index.js`的内容如下:
@ -727,7 +727,7 @@ $(function () {
最终的页面如下:
![Book list](./images/booktore-book-list-2.png)
![Book list](./images/bookstore-book-list-2.png)
{{end}}
@ -760,7 +760,7 @@ yarn
yarn ng generate module book --routing true
```
![Generating book module](./images/booktore-creating-book-module-terminal.png)
![Generating book module](./images/bookstore-creating-book-module-terminal.png)
#### 路由
@ -793,7 +793,7 @@ import { ApplicationLayoutComponent } from '@abp/ng.theme.basic'; //==> added th
yarn ng generate component book/book-list
```
![Creating book list](./images/booktore-creating-book-list-terminal.png)
![Creating book list](./images/bookstore-creating-book-list-terminal.png)
打开 `app\book` 目录下的 `book.module.ts` 文件,使用以下内容替换它:
@ -849,7 +849,7 @@ yarn start
我们将看到book页面的 **book-list works!**:
![Initial book list page](./images/booktore-initial-book-list-page.png)
![Initial book list page](./images/bookstore-initial-book-list-page.png)
#### 创建 BookState
@ -1048,11 +1048,11 @@ export class BookListComponent implements OnInit {
现在你可以在浏览器看到最终结果:
![Book list final result](./images/booktore-book-list.png)
![Book list final result](./images/bookstore-book-list.png)
项目的文件系统结构:
![Book list final result](./images/booktore-angular-file-tree.png)
![Book list final result](./images/bookstore-angular-file-tree.png)
在本教程中我们遵循了官方的[Angular风格指南](https://angular.io/guide/styleguide#file-tree).

26
docs/zh-Hans/Tutorials/Part-2.md

@ -29,7 +29,7 @@ end
- **Part 2: 创建,编辑,删除书籍(本章)**
- [Part-3: 集成测试](Part-3.md)
> 你也可以观看由ABP社区成员为本教程录制的[视频课程](https://amazingsolutions.teachable.com/p/lets-build-the-booktore-application).
> 你也可以观看由ABP社区成员为本教程录制的[视频课程](https://amazingsolutions.teachable.com/p/lets-build-the-bookstore-application).
{{if UI == "MVC"}}
@ -37,13 +37,13 @@ end
通过本节, 你将会了解如何创建一个 modal form 来实现新增书籍的功能. 最终成果如下图所示:
![booktore-create-dialog](./images/booktore-create-dialog-2.png)
![bookstore-create-dialog](./images/bookstore-create-dialog-2.png)
#### 新建 modal form
`Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个 `CreateModal.cshtml` Razor页面:
![booktore-add-create-dialog](./images/booktore-add-create-dialog-v2.png)
![bookstore-add-create-dialog](./images/bookstore-add-create-dialog-v2.png)
##### CreateModal.cshtml.cs
@ -130,7 +130,7 @@ namespace Acme.BookStore.Web.Pages.Books
如下图所示,只是在表格 **右上方** 添加了 **New book** 按钮:
![booktore-new-book-button](./images/booktore-new-book-button.png)
![bookstore-new-book-button](./images/bookstore-new-book-button.png)
打开 `Pages/book/index.js``datatable` 配置代码后面添加如下代码:
@ -155,7 +155,7 @@ $('#NewBookButton').click(function (e) {
`Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个名叫 `EditModal.cshtml` 的Razor页面:
![booktore-add-edit-dialog](./images/booktore-add-edit-dialog.png)
![bookstore-add-edit-dialog](./images/bookstore-add-edit-dialog.png)
#### EditModal.cshtml.cs
@ -258,7 +258,7 @@ namespace Acme.BookStore.Web
我们将为表格每行添加下拉按钮 ("Actions") . 最终效果如下:
![booktore-book-table-actions](images/booktore-book-table-actions.png)
![bookstore-book-table-actions](images/bookstore-book-table-actions.png)
打开 `Pages/Books/Index.cshtml` 页面,并按下方所示修改表格部分的代码:
@ -450,6 +450,8 @@ $(function () {
{{end}}
{{if UI == "NG"}}
### 新增 Book 实体
下面的章节中,你将学习到如何创建一个新的模态对话框来新增Book实体.
@ -654,7 +656,7 @@ export class BookListComponent implements OnInit {
你可以打开浏览器,点击**New book**按钮看到模态框.
![Empty modal for new book](./images/booktore-empty-new-book-modal.png)
![Empty modal for new book](./images/bookstore-empty-new-book-modal.png)
#### 添加响应式表单
@ -878,7 +880,7 @@ export class BookListComponent implements OnInit {
现在你可以打开浏览器看到以下变化:
![New book modal](./images/booktore-new-book-form.png)
![New book modal](./images/bookstore-new-book-form.png)
#### 保存图书
@ -990,7 +992,7 @@ export class BookListComponent implements OnInit {
模态框最终看起来像这样:
![Save button to the modal](./images/booktore-new-book-form-v2.png)
![Save button to the modal](./images/bookstore-new-book-form-v2.png)
### 更新图书
@ -1192,7 +1194,7 @@ export class BookListComponent implements OnInit {
UI最终看起来像这样:
![Action buttons](./images/booktore-actions-buttons.png)
![Action buttons](./images/bookstore-actions-buttons.png)
打开 `app\app\book\book-list` 文件夹下的 `book-list.component.html` 文件,使用以下内容替换 `<ng-template #abpHeader>` 标签:
@ -1322,7 +1324,7 @@ delete(id: string) {
`delete` 方法会显示一个确认弹层并订阅用户响应. 只在用户点击 `Yes` 按钮时分派动作. 确认弹层看起来如下:
![booktore-confirmation-popup](./images/booktore-confirmation-popup.png)
![bookstore-confirmation-popup](./images/bookstore-confirmation-popup.png)
#### 添加删除按钮
@ -1339,7 +1341,7 @@ delete(id: string) {
最终操作下拉框UI看起来如下:
![booktore-final-actions-dropdown](./images/booktore-final-actions-dropdown.png)
![bookstore-final-actions-dropdown](./images/bookstore-final-actions-dropdown.png)
{{end}}

474
docs/zh-Hans/UI/Angular/Component-Replacement.md

@ -15,16 +15,20 @@ import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddRepl
import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum
import { Store } from '@ngxs/store'; // imported Store
//...
export class AppComponent {
@Component(/* component metadata */)
export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
// added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: YourNewRoleComponent,
key: eIdentityComponents.Roles,
}),
);
//...
}
}
@ -54,7 +58,7 @@ yarn ng generate component shared/my-application-layout --export --entryComponen
<router-outlet></router-outlet>
```
打开 `app.component.ts` 添加以下内容:
打开 `src/app` 文件夹下的 `app.component.ts` 文件添加以下内容:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
@ -62,11 +66,13 @@ import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeB
import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent
import { Store } from '@ngxs/store'; // imported Store
//...
export class AppComponent {
@Component(/* component metadata */)
export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
// added below content
// added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: MyApplicationLayoutComponent,
@ -79,6 +85,464 @@ export class AppComponent {
}
```
### 布局组件
![Layout Components](./images/layout-components.png)
#### 如何替换LogoComponent
![LogoComponent](./images/logo-component.png)
`angular` 目录下运行以下命令创建新的组件 `LogoComponent`:
```bash
yarn ng generate component logo --inlineTemplate --inlineStyle --entryComponent
# You don't need the --entryComponent option in Angular 9
```
打开 `src/app/logo` 目录下生成的 `logo.component.ts` 并使用以下内容替换它:
```js
import { Component } from '@angular/core';
@Component({
selector: 'app-logo',
template: `
<a class="navbar-brand" routerLink="/">
<!-- Change the img src -->
<img
src="https://via.placeholder.com/100x50/343a40/FF0000?text=MyLogo"
alt="logo"
width="100%"
height="auto"
/>
</a>
`,
})
export class LogoComponent {}
```
打开 `src/app` 目录下的 `app.component.ts` 做以下修改:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { Store } from '@ngxs/store'; // imported Store
import { LogoComponent } from './logo/logo.component'; // imported NavItemsComponent
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents
//...
@Component(/* component metadata */)
export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
//...
// added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: LogoComponent,
key: eThemeBasicComponents.Logo,
}),
);
}
}
```
最终UI如下:
![New logo](./images/replaced-logo-component.png)
#### 如何替换RoutesComponent
![RoutesComponent](./images/routes-component.png)
`angular` 目录下运行以下命令创建新的组件 `RoutesComponent`:
```bash
yarn ng generate component routes --entryComponent
# You don't need the --entryComponent option in Angular 9
```
打开 `src/app/routes` 目录下生成的 `routes.component.ts` 并使用以下内容替换它:
```js
import { ABP, ReplaceableComponents } from '@abp/ng.core';
import {
Component,
HostBinding,
Inject,
Renderer2,
TrackByFunction,
AfterViewInit,
} from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
@Component({
selector: 'app-routes',
templateUrl: 'routes.component.html',
})
export class RoutesComponent implements AfterViewInit {
@HostBinding('class.mx-auto')
marginAuto = true;
smallScreen = window.innerWidth < 992;
constructor(private renderer: Renderer2) {}
ngAfterViewInit() {
fromEvent(window, 'resize')
.pipe(debounceTime(150))
.subscribe(() => {
this.smallScreen = window.innerWidth < 992;
});
}
}
```
打开 `src/app/routes` 目录下生成的 `routes.component.html` 并使用以下内容替换它:
```html
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" routerLink="/"
><i class="fas fa-home"></i> {%{{{ '::Menu:Home' | abpLocalization }}}%}</a
>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/my-page"><i class="fas fa-newspaper mr-1"></i>My Page</a>
</li>
<li
#navbarRootDropdown
[abpVisibility]="routeContainer"
class="nav-item dropdown"
display="static"
(click)="
navbarRootDropdown.expand
? (navbarRootDropdown.expand = false)
: (navbarRootDropdown.expand = true)
"
>
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
<i class="fas fa-wrench"></i>
{%{{{ 'AbpUiNavigation::Menu:Administration' | abpLocalization }}}%}
</a>
<div
#routeContainer
class="dropdown-menu border-0 shadow-sm"
(click)="$event.preventDefault(); $event.stopPropagation()"
[class.d-block]="smallScreen && navbarRootDropdown.expand"
>
<div
class="dropdown-submenu"
ngbDropdown
#dropdownSubmenu="ngbDropdown"
placement="right-top"
[autoClose]="true"
*abpPermission="'AbpIdentity.Roles || AbpIdentity.Users'"
>
<div ngbDropdownToggle [class.dropdown-toggle]="false">
<a
abpEllipsis="210px"
[abpEllipsisEnabled]="!smallScreen"
role="button"
class="btn d-block text-left dropdown-toggle"
>
<i class="fa fa-id-card-o"></i>
{%{{{ 'AbpIdentity::Menu:IdentityManagement' | abpLocalization }}}%}
</a>
</div>
<div
#childrenContainer
class="dropdown-menu border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()"
>
<div class="dropdown-submenu" *abpPermission="'AbpIdentity.Roles'">
<a class="dropdown-item" routerLink="/identity/roles">
{%{{{ 'AbpIdentity::Roles' | abpLocalization }}}%}</a
>
</div>
<div class="dropdown-submenu" *abpPermission="'AbpIdentity.Users'">
<a class="dropdown-item" routerLink="/identity/users">
{%{{{ 'AbpIdentity::Users' | abpLocalization }}}%}</a
>
</div>
</div>
</div>
<div
class="dropdown-submenu"
ngbDropdown
#dropdownSubmenu="ngbDropdown"
placement="right-top"
[autoClose]="true"
*abpPermission="'AbpTenantManagement.Tenants'"
>
<div ngbDropdownToggle [class.dropdown-toggle]="false">
<a
abpEllipsis="210px"
[abpEllipsisEnabled]="!smallScreen"
role="button"
class="btn d-block text-left dropdown-toggle"
>
<i class="fa fa-users"></i>
{%{{{ 'AbpTenantManagement::Menu:TenantManagement' | abpLocalization }}}%}
</a>
</div>
<div
#childrenContainer
class="dropdown-menu border-0 shadow-sm"
[class.d-block]="smallScreen && dropdownSubmenu.isOpen()"
>
<div class="dropdown-submenu" *abpPermission="'AbpTenantManagement.Tenants'">
<a class="dropdown-item" routerLink="/tenant-management/tenants">
{%{{{ 'AbpTenantManagement::Tenants' | abpLocalization }}}%}</a
>
</div>
</div>
</div>
</div>
</li>
</ul>
```
打开 `src/app` 目录下的 `app.component.ts` 做以下修改:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { Store } from '@ngxs/store'; // imported Store
import { RoutesComponent } from './routes/routes.component'; // imported NavItemsComponent
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents
//...
@Component(/* component metadata */)
export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
//...
// added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: RoutesComponent,
key: eThemeBasicComponents.Routes,
}),
);
}
}
```
最终UI如下:
![New routes](./images/replaced-routes-component.png)
#### 如何替换NavItemsComponent
![NavItemsComponent](./images/nav-items-component.png)
`angular` 目录下运行以下命令创建新的组件 `NavItemsComponent`:
```bash
yarn ng generate component nav-items --entryComponent
# You don't need the --entryComponent option in Angular 9
```
打开 `src/app/nav-items` 目录下生成的 `nav-items.component.ts` 并使用以下内容替换它:
```js
import {
ApplicationConfiguration,
AuthService,
ConfigState,
SessionState,
SetLanguage,
} from '@abp/ng.core';
import { Component, AfterViewInit } from '@angular/core';
import { Navigate, RouterState } from '@ngxs/router-plugin';
import { Select, Store } from '@ngxs/store';
import { Observable, fromEvent } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
import snq from 'snq';
@Component({
selector: 'app-nav-items',
templateUrl: 'nav-items.component.html',
})
export class NavItemsComponent implements AfterViewInit {
@Select(ConfigState.getOne('currentUser'))
currentUser$: Observable<ApplicationConfiguration.CurrentUser>;
@Select(ConfigState.getDeep('localization.languages'))
languages$: Observable<ApplicationConfiguration.Language[]>;
smallScreen = window.innerWidth < 992;
get defaultLanguage$(): Observable<string> {
return this.languages$.pipe(
map(
languages =>
snq(
() => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName,
),
'',
),
);
}
get dropdownLanguages$(): Observable<ApplicationConfiguration.Language[]> {
return this.languages$.pipe(
map(
languages =>
snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)),
[],
),
);
}
get selectedLangCulture(): string {
return this.store.selectSnapshot(SessionState.getLanguage);
}
constructor(private store: Store, private authService: AuthService) {}
ngAfterViewInit() {
fromEvent(window, 'resize')
.pipe(debounceTime(150))
.subscribe(() => {
this.smallScreen = window.innerWidth < 992;
});
}
onChangeLang(cultureName: string) {
this.store.dispatch(new SetLanguage(cultureName));
}
logout() {
this.authService.logout().subscribe(() => {
this.store.dispatch(
new Navigate(['/'], null, {
state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url },
}),
);
});
}
}
```
打开 `src/app/nav-items` 目录下生成的 `nav-items.component.html` 并使用以下内容替换它:
```html
<ul class="navbar-nav">
<input type="search" placeholder="Search" class="bg-transparent border-0 text-white" />
<li *ngIf="(dropdownLanguages$ | async)?.length > 0" class="nav-item">
<div class="dropdown" ngbDropdown #languageDropdown="ngbDropdown" display="static">
<a
ngbDropdownToggle
class="nav-link"
href="javascript:void(0)"
role="button"
id="dropdownMenuLink"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
{%{{{ defaultLanguage$ | async }}}%}
</a>
<div
class="dropdown-menu dropdown-menu-right border-0 shadow-sm"
aria-labelledby="dropdownMenuLink"
[class.d-block]="smallScreen && languageDropdown.isOpen()"
>
<a
*ngFor="let lang of dropdownLanguages$ | async"
href="javascript:void(0)"
class="dropdown-item"
(click)="onChangeLang(lang.cultureName)"
>{%{{{ lang?.displayName }}}%}</a
>
</div>
</div>
</li>
<li class="nav-item">
<ng-template #loginBtn>
<a role="button" class="nav-link" routerLink="/account/login">{%{{{
'AbpAccount::Login' | abpLocalization
}}}%}</a>
</ng-template>
<div
*ngIf="(currentUser$ | async)?.isAuthenticated; else loginBtn"
ngbDropdown
class="dropdown"
#currentUserDropdown="ngbDropdown"
display="static"
>
<a
ngbDropdownToggle
class="nav-link"
href="javascript:void(0)"
role="button"
id="dropdownMenuLink"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
{%{{{ (currentUser$ | async)?.userName }}}%}
</a>
<div
class="dropdown-menu dropdown-menu-right border-0 shadow-sm"
aria-labelledby="dropdownMenuLink"
[class.d-block]="smallScreen && currentUserDropdown.isOpen()"
>
<a class="dropdown-item" routerLink="/account/manage-profile"
><i class="fa fa-cog mr-1"></i>{%{{{ 'AbpAccount::ManageYourProfile' | abpLocalization }}}%}</a
>
<a class="dropdown-item" href="javascript:void(0)" (click)="logout()"
><i class="fa fa-power-off mr-1"></i>{%{{{ 'AbpUi::Logout' | abpLocalization }}}%}</a
>
</div>
</div>
</li>
</ul>
```
打开 `src/app` 目录下的 `app.component.ts` 做以下修改:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { Store } from '@ngxs/store'; // imported Store
import { NavItemsComponent } from './nav-items/nav-items.component'; // imported NavItemsComponent
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents
//...
@Component(/* component metadata */)
export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
//...
// added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: NavItemsComponent,
key: eThemeBasicComponents.NavItems,
}),
);
}
}
```
最终UI如下:
![New nav-items](./images/replaced-nav-items-component.png)
## 下一步是什么?
- [自定义设置页面](./Custom-Setting-Page.md)
- [自定义设置页面](./Custom-Setting-Page.md)

62
docs/zh-Hans/UI/Angular/Localization.md

@ -130,6 +130,68 @@ this.store.selectSnapshot(
本地化资源存储在 `ConfigState``localization` 属性中.
## RTL支持
从v2.9开始,ABP支持RTL. 如果使用v2.9及更高版本生成新项目,你无需进行任何更改. 如果要从早期版本迁移项目,请按照以下2个步骤操作:
#### 步骤 1. 为 Bootstrap LRT和RTL创建Chunks
在[angular.json中找到样式配置](https://angular.io/guide/workspace-config#style-script-config)确保项目中的chunks含有 `bootstrap-rtl.min``bootstrap-ltr.min`:
```json
{
"projects": {
"MyProjectName": {
"architect": {
"build": {
"options": {
"styles": [
{
"input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css",
"inject": false,
"bundleName": "bootstrap-rtl.min"
},
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true,
"bundleName": "bootstrap-ltr.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
"inject": true,
"bundleName": "fontawesome-all.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
"inject": true,
"bundleName": "fontawesome-v4-shims.min"
},
"apps/dev-app/src/styles.scss"
],
}
}
}
}
}
}
#### 步骤 2. 清除AppComponent中延迟加载的Fontawesome
如果你如上所述为Fontawesome创建并且注入了chunks,就不再需要v2.9版本之前的实现的 `AppComponent` 延迟加载. 删除它们即可,新版的 `AppComponent` 如下所示:
```js
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<abp-loader-bar></abp-loader-bar>
<router-outlet></router-outlet>
`,
})
export class AppComponent {}
```
## 另请参阅
* [ASP.NET Core中的本地化](../../Localization.md)

13
docs/zh-Hans/docs-nav.json

@ -430,6 +430,10 @@
"text": "到PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": " Oracle",
"path": "Entity-Framework-Core-Oracle.md"
},
{
"text": "到SQLite",
"path": "Entity-Framework-Core-SQLite.md"
@ -450,6 +454,15 @@
}
]
},
{
"text": "实时",
"items": [
{
"text": "SignalR集成",
"path": "SignalR-Integration.md"
}
]
},
{
"text": "后台服务",
"items": [

BIN
docs/zh-Hans/images/hello-template.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
docs/zh-Hans/images/multiple-file-template.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelper.cs

@ -1,5 +1,7 @@
using System;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
@ -8,17 +10,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
{
public abstract class AbpTagHelper : TagHelper, ITransientDependency
{
}
public abstract class AbpTagHelper<TTagHelper, TService> : AbpTagHelper
where TTagHelper : AbpTagHelper<TTagHelper, TService>
where TService : class, IAbpTagHelperService<TTagHelper>
where TService : class, IAbpTagHelperService<TTagHelper>
{
protected TService Service { get; }
public override int Order => Service.Order;
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected AbpTagHelper(TService service)
{
Service = service;
@ -40,4 +46,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
return Service.ProcessAsync(context, output);
}
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs

@ -12,10 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
[HtmlAttributeName("abp-model")]
public ModelExpression Model { get; set; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public bool? SubmitButton { get; set; }
public bool? RequiredSymbols { get; set; } = true;

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs

@ -29,15 +29,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
[HtmlAttributeName("required-symbol")]
public bool DisplayRequiredSymbol { get; set; } = true;
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
[HtmlAttributeName("asp-format")]
public string Format { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public AbpInputTagHelper(AbpInputTagHelperService tagHelperService)

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs

@ -18,10 +18,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public IEnumerable<SelectListItem> AspItems { get; set; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public AbpRadioInputTagHelper(AbpRadioInputTagHelperService tagHelperService)
: base(tagHelperService)
{

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs

@ -21,10 +21,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
[HtmlAttributeName("required-symbol")]
public bool DisplayRequiredSymbol { get; set; } = true;
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public AbpSelectTagHelper(AbpSelectTagHelperService tagHelperService)
: base(tagHelperService)
{

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelper.cs

@ -11,10 +11,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
public bool? ShowInfo { get; set; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public AbpPaginationTagHelper(AbpPaginationTagHelperService tagHelperService)
: base(tagHelperService)
{

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelper.cs

@ -3,9 +3,9 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public abstract class AbpBundleItemTagHelper<TTagHelper, TTagHelperService> : AbpTagHelper<TTagHelper, TTagHelperService>, IBundleItemTagHelper
public abstract class AbpBundleItemTagHelper<TTagHelper, TTagHelperService> : AbpTagHelper<TTagHelper, TTagHelperService>, IBundleItemTagHelper
where TTagHelper : AbpTagHelper<TTagHelper, TTagHelperService>, IBundleItemTagHelper
where TTagHelperService: AbpBundleItemTagHelperService<TTagHelper>
where TTagHelperService: AbpBundleItemTagHelperService<TTagHelper, TTagHelperService>
{
/// <summary>
/// A file path.
@ -57,4 +57,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
protected abstract string GetFileExtension();
}
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs

@ -5,8 +5,9 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public abstract class AbpBundleItemTagHelperService<TTagHelper> : AbpTagHelperService<TTagHelper>
where TTagHelper : TagHelper, IBundleItemTagHelper
public abstract class AbpBundleItemTagHelperService<TTagHelper, TService> : AbpTagHelperService<TTagHelper>
where TTagHelper : AbpTagHelper<TTagHelper, TService>, IBundleItemTagHelper
where TService : class, IAbpTagHelperService<TTagHelper>
{
protected AbpTagHelperResourceService ResourceService { get; }
@ -26,6 +27,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
else
{
await ResourceService.ProcessAsync(
TagHelper.ViewContext,
context,
output,
new List<BundleTagHelperItem>
@ -37,4 +39,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
}
}
}
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs

@ -5,8 +5,9 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public abstract class AbpBundleTagHelperService<TTagHelper> : AbpTagHelperService<TTagHelper>
where TTagHelper : TagHelper, IBundleTagHelper
public abstract class AbpBundleTagHelperService<TTagHelper, TService> : AbpTagHelperService<TTagHelper>
where TTagHelper : AbpTagHelper<TTagHelper, TService>, IBundleTagHelper
where TService : class, IAbpTagHelperService<TTagHelper>
{
protected AbpTagHelperResourceService ResourceService { get; }
@ -18,6 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
await ResourceService.ProcessAsync(
TagHelper.ViewContext,
context,
output,
await GetBundleItems(context, output),
@ -33,4 +35,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
return bundleItems;
}
}
}
}

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptBundleTagHelperService.cs

@ -1,10 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public class AbpScriptBundleTagHelperService : AbpBundleTagHelperService<AbpScriptBundleTagHelper>
public class AbpScriptBundleTagHelperService : AbpBundleTagHelperService<AbpScriptBundleTagHelper, AbpScriptBundleTagHelperService>
{
public AbpScriptBundleTagHelperService(AbpTagHelperScriptService resourceHelper)
public AbpScriptBundleTagHelperService(AbpTagHelperScriptService resourceHelper)
: base(resourceHelper)
{
}
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptTagHelperService.cs

@ -1,10 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public class AbpScriptTagHelperService : AbpBundleItemTagHelperService<AbpScriptTagHelper>
public class AbpScriptTagHelperService : AbpBundleItemTagHelperService<AbpScriptTagHelper, AbpScriptTagHelperService>
{
public AbpScriptTagHelperService(AbpTagHelperScriptService resourceService)
: base(resourceService)
{
}
}
}
}

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleBundleTagHelperService.cs

@ -1,10 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public class AbpStyleBundleTagHelperService : AbpBundleTagHelperService<AbpStyleBundleTagHelper>
public class AbpStyleBundleTagHelperService : AbpBundleTagHelperService<AbpStyleBundleTagHelper, AbpStyleBundleTagHelperService>
{
public AbpStyleBundleTagHelperService(AbpTagHelperStyleService resourceHelper)
public AbpStyleBundleTagHelperService(AbpTagHelperStyleService resourceHelper)
: base(resourceHelper)
{
}
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleTagHelperService.cs

@ -1,10 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
{
public class AbpStyleTagHelperService : AbpBundleItemTagHelperService<AbpStyleTagHelper>
public class AbpStyleTagHelperService : AbpBundleItemTagHelperService<AbpStyleTagHelper, AbpStyleTagHelperService>
{
public AbpStyleTagHelperService(AbpTagHelperStyleService resourceService)
: base(resourceService)
{
}
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs

@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@ -20,7 +22,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
protected IWebContentFileProvider WebContentFileProvider { get; }
protected IWebHostEnvironment HostingEnvironment { get; }
protected readonly AbpBundlingOptions Options;
protected AbpTagHelperResourceService(
IBundleManager bundleManager,
IWebContentFileProvider webContentFileProvider,
@ -36,11 +38,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
}
public virtual async Task ProcessAsync(
[NotNull] ViewContext viewContext,
[NotNull] TagHelperContext context,
[NotNull] TagHelperOutput output,
[NotNull] List<BundleTagHelperItem> bundleItems,
[CanBeNull] string bundleName = null)
{
Check.NotNull(viewContext, nameof(viewContext));
Check.NotNull(context, nameof(context));
Check.NotNull(output, nameof(output));
Check.NotNull(bundleItems, nameof(bundleItems));
@ -69,7 +73,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
throw new AbpException($"Could not find the bundle file '{bundleFile}' from {nameof(IWebContentFileProvider)}");
}
AddHtmlTag(context, output, bundleFile + "?_v=" + file.LastModified.UtcTicks);
AddHtmlTag(viewContext, context, output, bundleFile + "?_v=" + file.LastModified.UtcTicks);
}
stopwatch.Stop();
@ -80,11 +84,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
protected abstract Task<IReadOnlyList<string>> GetBundleFilesAsync(string bundleName);
protected abstract void AddHtmlTag(TagHelperContext context, TagHelperOutput output, string file);
protected abstract void AddHtmlTag(ViewContext viewContext, TagHelperContext context, TagHelperOutput output, string file);
protected virtual string GenerateBundleName(List<BundleTagHelperItem> bundleItems)
{
return bundleItems.JoinAsString("|").ToMd5();
}
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs

@ -3,7 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.VirtualFileSystem;
@ -39,9 +43,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
return await BundleManager.GetScriptBundleFilesAsync(bundleName);
}
protected override void AddHtmlTag(TagHelperContext context, TagHelperOutput output, string file)
protected override void AddHtmlTag(ViewContext viewContext, TagHelperContext context, TagHelperOutput output, string file)
{
output.Content.AppendHtml($"<script src=\"{file}\"></script>{Environment.NewLine}");
output.Content.AppendHtml($"<script src=\"{viewContext.GetUrlHelper().Content(file.EnsureStartsWith('~'))}\"></script>{Environment.NewLine}");
}
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs

@ -3,7 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.VirtualFileSystem;
@ -39,9 +43,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
return await BundleManager.GetStyleBundleFilesAsync(bundleName);
}
protected override void AddHtmlTag(TagHelperContext context, TagHelperOutput output, string file)
protected override void AddHtmlTag(ViewContext viewContext, TagHelperContext context, TagHelperOutput output, string file)
{
output.Content.AppendHtml($"<link rel=\"stylesheet\" href=\"{file}\" />{Environment.NewLine}");
output.Content.AppendHtml($"<link rel=\"stylesheet\" href=\"{viewContext.GetUrlHelper().Content(file.EnsureStartsWith('~'))}\" />{Environment.NewLine}");
}
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json

@ -9,4 +9,4 @@
"SwitchTenant": "Změnit tenant",
"NotSelected": "Nevybrán"
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js

@ -104,7 +104,7 @@
locale: abp.localization.currentCulture.name
}).toLocaleString();
},
getOptions($input) { //$input may needed if developer wants to override this method
getOptions: function($input) { //$input may needed if developer wants to override this method
return {
todayBtn: "linked",
autoclose: true,

15
framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/ViewFeatures/ViewContextExtensions.cs

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
{
public static class ViewContextExtensions
{
public static IUrlHelper GetUrlHelper(this ViewContext viewContext)
{
var urlHelperFactory = viewContext.HttpContext.RequestServices.GetRequiredService<IUrlHelperFactory>();
return urlHelperFactory.GetUrlHelper(viewContext);
}
}
}

6
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/cs.json

@ -0,0 +1,6 @@
{
"culture": "cs",
"texts": {
"MaxResultCountExceededExceptionMessage": "{0} nemůže být více než {1}! Navyšte {2}.{3} na straně serveru pro více výsledků."
}
}

5
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json

@ -18,7 +18,8 @@
"Description:Abp.Mailing.Smtp.Password": "Heslo pro uživatelské jméno spojené s přihlašovacími údaji.",
"Description:Abp.Mailing.Smtp.Domain": "Název domény nebo počítače, který ověřuje přihlašovací údaje.",
"Description:Abp.Mailing.Smtp.EnableSsl": "Zda SmtpClient používá SSL k šifrování připojení.",
"Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Zda jsou výchozí přihlašovací údaje odesílány s požadavky."
"Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Zda jsou výchozí přihlašovací údaje odesílány s požadavky.",
"TextTemplate:StandardEmailTemplates.Layout": "Výchozí šablona rozložení emailu",
"TextTemplate:StandardEmailTemplates.Message": "Jednoduchá šablona zprávy pro emaily"
}
}

51
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Newtonsoft.Json;
@ -14,8 +15,6 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
public ICancellationTokenProvider CancellationTokenProvider { get; set; }
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; }
protected IApiDescriptionCache Cache { get; }
private static readonly JsonSerializerSettings SharedJsonSerializerSettings = new JsonSerializerSettings
@ -23,18 +22,15 @@ namespace Volo.Abp.Http.Client.DynamicProxying
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
public ApiDescriptionFinder(
IApiDescriptionCache cache,
IDynamicProxyHttpClientFactory httpClientFactory)
public ApiDescriptionFinder(IApiDescriptionCache cache)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
CancellationTokenProvider = NullCancellationTokenProvider.Instance;
}
public async Task<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo method)
public async Task<ActionApiDescriptionModel> FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo method)
{
var apiDescription = await GetApiDescriptionAsync(baseUrl);
var apiDescription = await GetApiDescriptionAsync(client, baseUrl);
//TODO: Cache finding?
@ -56,8 +52,8 @@ namespace Volo.Abp.Http.Client.DynamicProxying
var found = true;
for (int i = 0; i < methodParameters.Length; i++)
{
if (!TypeMatches(action.ParametersOnMethod[i], methodParameters[i]))
{
if (!TypeMatches(action.ParametersOnMethod[i], methodParameters[i]))
{
found = false;
break;
@ -76,33 +72,30 @@ namespace Volo.Abp.Http.Client.DynamicProxying
throw new AbpException($"Could not found remote action for method: {method} on the URL: {baseUrl}");
}
public virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(string baseUrl)
public virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(HttpClient client, string baseUrl)
{
return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl));
return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(client, baseUrl));
}
protected virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionFromServerAsync(string baseUrl)
protected virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionFromServerAsync(HttpClient client, string baseUrl)
{
using (var client = HttpClientFactory.Create())
{
var response = await client.GetAsync(
baseUrl.EnsureEndsWith('/') + "api/abp/api-definition",
CancellationTokenProvider.Token
);
var response = await client.GetAsync(
baseUrl.EnsureEndsWith('/') + "api/abp/api-definition",
CancellationTokenProvider.Token
);
if (!response.IsSuccessStatusCode)
{
throw new AbpException("Remote service returns error! StatusCode = " + response.StatusCode);
}
if (!response.IsSuccessStatusCode)
{
throw new AbpException("Remote service returns error! StatusCode = " + response.StatusCode);
}
var content = await response.Content.ReadAsStringAsync();
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject(
content,
typeof(ApplicationApiDescriptionModel), SharedJsonSerializerSettings);
var result = JsonConvert.DeserializeObject(
content,
typeof(ApplicationApiDescriptionModel), SharedJsonSerializerSettings);
return (ApplicationApiDescriptionModel)result;
}
return (ApplicationApiDescriptionModel)result;
}
protected virtual bool TypeMatches(MethodParameterApiDescriptionModel actionParameter, ParameterInfo methodParameter)

6
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -106,7 +106,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
private async Task<T> MakeRequestAndGetResultAsync<T>(IAbpMethodInvocation invocation)
{
var responseAsString = await MakeRequestAsync(invocation);
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(responseAsString, typeof(T));
@ -122,7 +122,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
var client = HttpClientFactory.Create(clientConfig.RemoteServiceName);
var action = await ApiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method);
var action = await ApiDescriptionFinder.FindActionAsync(client, remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method);
var apiVersion = GetApiVersionInfo(action);
var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion);
@ -252,4 +252,4 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return CancellationTokenProvider.Token;
}
}
}
}

7
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs

@ -1,4 +1,5 @@
using System;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Volo.Abp.Http.Modeling;
@ -7,8 +8,8 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
public interface IApiDescriptionFinder
{
Task<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo invocationMethod);
Task<ActionApiDescriptionModel> FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo invocationMethod);
Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(string baseUrl);
Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(HttpClient client, string baseUrl);
}
}
}

2
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json

@ -2,6 +2,6 @@
"culture": "cs",
"texts": {
"DisplayName:Abp.Localization.DefaultLanguage": "Výchozí jazyk",
"Description:Abp.Localization.DefaultLanguage": "Váchozí jazyk aplikace."
"Description:Abp.Localization.DefaultLanguage": "Výchozí jazyk aplikace."
}
}

7
framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/cs.json

@ -0,0 +1,7 @@
{
"culture": "cs",
"texts": {
"DisplayName:Abp.Timing.Timezone": "Časové pásmo",
"Description:Abp.Timing.Timezone": "Časové pásmo aplikace"
}
}

2
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json

@ -3,4 +3,4 @@
"texts": {
"Menu:Administration": "Administrace"
}
}
}

8
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json

@ -13,11 +13,13 @@
"DefaultErrorMessage404": "Prostředek nenalezen!",
"DefaultErrorMessage404Detail": "Vyžádaný prostředek nebyl na serveru nalezen!",
"EntityNotFoundErrorMessage": "Neexistující entita {0} s id = {1}!",
"Languages": "Jazyky",
"Error": "Chyba",
"AreYouSure": "Jste si jisti?",
"Cancel": "Zrušit",
"Yes": "Ano",
"No": "Ne",
"Ok": "Ok",
"Close": "Zavřít",
"Save": "Uložit",
"SavingWithThreeDot": "Ukládám...",
@ -25,6 +27,8 @@
"Delete": "Smazat",
"Edit": "Upravit",
"Refresh": "Obnovit",
"Language": "Jazyk",
"LoadMore": "Načíst více",
"ProcessingWithThreeDot": "Zpracovávám...",
"LoadingWithThreeDot": "Nahrávám...",
"Welcome": "Vítejte",
@ -42,7 +46,7 @@
"PagerInfo{0}{1}{2}": "Zobrazeno od {0} do {1} z celkem {2} záznamů",
"PagerInfoEmpty": "Zobrazeno od 0 do 0 z celkem 0 záznamů",
"PagerInfoFiltered": "(filtrováno ze všech _MAX_ záznamů)",
"NoDataAvailableInDatatable": "V tabulce nejsou žádná data",
"NoDataAvailableInDatatable": "Nejsou žádná data",
"PagerShowMenuEntries": "Zobrazit _MENU_ záznamů",
"DatatableActionDropdownDefaultText": "Akce",
"ChangePassword": "Změnit heslo",
@ -56,4 +60,4 @@
"GoHomePage": "Přejít na domovskou stránku",
"GoBack": "Jít zpět"
}
}
}

2
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json

@ -31,4 +31,4 @@
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "Pole není platná plně kvalifikovaná adresa http, https, nebo ftp URL.",
"ThisFieldIsInvalid.": "Pole je neplatné."
}
}
}

4
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/cs.json

@ -2,6 +2,6 @@
"culture": "cs",
"texts": {
"BirthDate": "Narozeniny",
"Value1": "Hodnota jedna"
"Value1": "Hodnota jedna"
}
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json

@ -0,0 +1,6 @@
{
"culture": "cs",
"texts": {
"hello": "Ahoj"
}
}

2
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json

@ -1,5 +1,5 @@
{
"culture": "de",
"culture": "en",
"texts": {
"hello": "Hello"
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/cs.json

@ -4,4 +4,4 @@
"USA": "Spojené státy americké",
"Brazil": "Brazílie"
}
}
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/cs.json

@ -4,4 +4,4 @@
"ThisFieldIsRequired": "Toto pole je povinné",
"MaxLenghtErrorMessage": "Toto pole může mít nanejvýš '{0}' znaků"
}
}
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json

@ -8,4 +8,4 @@
"Universe": "Vesmír",
"FortyTwo": "Čtyřicet dva"
}
}
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json

@ -3,4 +3,4 @@
"texts": {
"SeeYou": "Měj se"
}
}
}

7
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/cs.json

@ -0,0 +1,7 @@
{
"culture": "cs",
"texts": {
"HelloText": "Ahoj {0}",
"HowAreYou": "jak se máš?"
}
}

3
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json

@ -11,6 +11,7 @@
"InvalidUserNameOrPassword": "Neplatné uživatelské jméno nebo heslo!",
"LoginIsNotAllowed": "Není vám dovoleno se přihlásit! Musíte první potvrdit email/telefonní číslo.",
"SelfRegistrationDisabledMessage": "Vlastní registrace uživatele není povolena. K vytvoření účtu kontaktujte správce.",
"LocalLoginDisabledMessage": "Místní přihlášení je pro tuto aplikaci zakázáno.",
"Login": "Přihlásit",
"Cancel": "Zrušit",
"Register": "Registrovat",
@ -41,4 +42,4 @@
"DisplayName:Abp.Account.EnableLocalLogin": "Ověření pomocí místního účtu",
"Description:Abp.Account.EnableLocalLogin": "Označuje, zda server umožní uživatelům ověřovat se pomocí místního účtu."
}
}
}

6
modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs

@ -16,8 +16,8 @@ namespace Volo.Abp.Account.Web
return Task.CompletedTask;
}
var uiResource = context.ServiceProvider.GetRequiredService<IStringLocalizer<AbpUiResource>>();
var accountResource = context.ServiceProvider.GetRequiredService<IStringLocalizer<AccountResource>>();
var uiResource = context.GetLocalizer<AbpUiResource>();
var accountResource = context.GetLocalizer<AccountResource>();
context.Menu.AddItem(new ApplicationMenuItem("Account.Manage", accountResource["ManageYourProfile"], url: "/Account/Manage", icon: "fa fa-cog", order: 1000, null));
context.Menu.AddItem(new ApplicationMenuItem("Account.Logout", uiResource["Logout"], url: "/Account/Logout", icon: "fa fa-power-off", order: int.MaxValue - 1000));
@ -25,4 +25,4 @@ namespace Volo.Abp.Account.Web
return Task.CompletedTask;
}
}
}
}

9
modules/blob-storing-database/Volo.Abp.BlobStoring.Database.sln

@ -23,6 +23,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Databa
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{9E416AD3-1EC8-439A-9CFD-AAFFA89E2AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlobStoring.Database.Host.ConsoleApp.ConsoleApp", "host\BlobStoring.Database.Host.ConsoleApp\src\BlobStoring.Database.Host.ConsoleApp.ConsoleApp\BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj", "{C3C4CB94-4F73-4D04-9076-8D98D5C6B475}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -61,6 +65,10 @@ Global
{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
{C3C4CB94-4F73-4D04-9076-8D98D5C6B475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3C4CB94-4F73-4D04-9076-8D98D5C6B475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3C4CB94-4F73-4D04-9076-8D98D5C6B475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3C4CB94-4F73-4D04-9076-8D98D5C6B475}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -74,6 +82,7 @@ Global
{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}
{C3C4CB94-4F73-4D04-9076-8D98D5C6B475} = {9E416AD3-1EC8-439A-9CFD-AAFFA89E2AEB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD}

21
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.sln

@ -0,0 +1,21 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlobStoring.Database.Host.ConsoleApp.ConsoleApp", "src\BlobStoring.Database.Host.ConsoleApp.ConsoleApp\BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj", "{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8067AED-2B6E-4134-AAF8-9101457D709A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2} = {E8067AED-2B6E-4134-AAF8-9101457D709A}
EndGlobalSection
EndGlobal

23
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobService.cs

@ -0,0 +1,23 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
public class BlobService : IBlobService, ITransientDependency
{
private readonly IBlobContainer<ProfilePictureContainer> _container;
public BlobService(IBlobContainer<ProfilePictureContainer> container)
{
_container = container;
}
public async Task SaveFile(string fileName = "File Name", string fileContent = "File Content")
{
await _container.SaveAsync(fileName, fileContent.GetBytes(), true);
Console.WriteLine($"File: {fileName} is successfully saved");
}
}
}

32
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="appsettings.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\..\..\..\framework\src\Volo.Abp.EntityFrameworkCore.SqlServer\Volo.Abp.EntityFrameworkCore.SqlServer.csproj" />
<ProjectReference Include="..\..\..\..\src\Volo.Abp.BlobStoring.Database.EntityFrameworkCore\Volo.Abp.BlobStoring.Database.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.4" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.2" />
</ItemGroup>
</Project>

32
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppHostedService.cs

@ -0,0 +1,32 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Volo.Abp;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
public class ConsoleAppConsoleAppHostedService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
using (var application = AbpApplicationFactory.Create<ConsoleAppConsoleAppModule>(options =>
{
options.UseAutofac();
options.Services.AddLogging(c => c.AddSerilog());
}))
{
application.Initialize();
var blobService = application.ServiceProvider.GetService<BlobService>();
await blobService.SaveFile("Test File 2", "Test Content 2");
application.Shutdown();
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}

56
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppModule.cs

@ -0,0 +1,56 @@
using BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.Database;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.SqlServer;
using Volo.Abp.Modularity;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(BlobStoringDatabaseEntityFrameworkCoreModule)
)]
public class ConsoleAppConsoleAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
ConfigureEntityFramework(context);
context.Services.AddSingleton<IBlobProvider, DatabaseBlobProvider>();
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.ProviderType = typeof(DatabaseBlobProvider);
});
});
}
private void ConfigureEntityFramework(ServiceConfigurationContext context)
{
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True;MultipleActiveResultSets=true";
});
context.Services.AddAbpDbContext<BlobStoringHostDbContext>(options =>
{
options.AddDefaultRepositories(true);
});
Configure<AbpDbContextOptions>(x =>
{
x.UseSqlServer();
});
}
}
}

20
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContext.cs

@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore
{
public class BlobStoringHostDbContext : AbpDbContext<BlobStoringHostDbContext>
{
public BlobStoringHostDbContext(DbContextOptions<BlobStoringHostDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ConfigureBlobStoring();
}
}
}

29
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContextFactory.cs

@ -0,0 +1,29 @@
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore
{
public class BlobStoringHostDbContextFactory : IDesignTimeDbContextFactory<BlobStoringHostDbContext>
{
public BlobStoringHostDbContext CreateDbContext(string[] args)
{
var configuration = BuildConfiguration();
var builder = new DbContextOptionsBuilder<BlobStoringHostDbContext>()
.UseSqlServer(configuration.GetConnectionString("Default"));
return new BlobStoringHostDbContext(builder.Options);
}
private static IConfigurationRoot BuildConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);
return builder.Build();
}
}
}

26
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbSchemaMigrator.cs

@ -0,0 +1,26 @@
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore
{
public class BlobStoringHostDbSchemaMigrator : IBlobStoringHostDbSchemaMigrator, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public BlobStoringHostDbSchemaMigrator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task MigrateAsync()
{
await _serviceProvider
.GetRequiredService<BlobStoringHostDbContext>()
.Database
.MigrateAsync();
}
}
}

9
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/IBlobStoringHostDbSchemaMigrator.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore
{
public interface IBlobStoringHostDbSchemaMigrator
{
Task MigrateAsync();
}
}

9
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/IBlobService.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
public interface IBlobService
{
Task SaveFile(string fileName = "File Name", string fileContent = "File Content");
}
}

97
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.Designer.cs

@ -0,0 +1,97 @@
// <auto-generated />
using System;
using BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.Abp.EntityFrameworkCore;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations
{
[DbContext(typeof(BlobStoringHostDbContext))]
[Migration("20200531134550_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<Guid>("ContainerId")
.HasColumnType("uniqueidentifier");
b.Property<byte[]>("Content")
.HasColumnType("varbinary(max)")
.HasMaxLength(2147483647);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(256)")
.HasMaxLength(256);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TenantId", "ContainerId", "Name");
b.ToTable("AbpBlobs");
});
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(128)")
.HasMaxLength(128);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TenantId", "Name");
b.ToTable("AbpBlobContainers");
});
#pragma warning restore 612, 618
}
}
}

62
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.cs

@ -0,0 +1,62 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpBlobContainers",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
ExtraProperties = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
TenantId = table.Column<Guid>(nullable: true),
Name = table.Column<string>(maxLength: 128, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobContainers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpBlobs",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
ExtraProperties = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
ContainerId = table.Column<Guid>(nullable: false),
TenantId = table.Column<Guid>(nullable: true),
Name = table.Column<string>(maxLength: 256, nullable: false),
Content = table.Column<byte[]>(maxLength: 2147483647, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobs", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AbpBlobContainers_TenantId_Name",
table: "AbpBlobContainers",
columns: new[] { "TenantId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_TenantId_ContainerId_Name",
table: "AbpBlobs",
columns: new[] { "TenantId", "ContainerId", "Name" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpBlobContainers");
migrationBuilder.DropTable(
name: "AbpBlobs");
}
}
}

108
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.Designer.cs

@ -0,0 +1,108 @@
// <auto-generated />
using System;
using BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.Abp.EntityFrameworkCore;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations
{
[DbContext(typeof(BlobStoringHostDbContext))]
[Migration("20200531143839_FK_Added")]
partial class FK_Added
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<Guid>("ContainerId")
.HasColumnType("uniqueidentifier");
b.Property<byte[]>("Content")
.HasColumnType("varbinary(max)")
.HasMaxLength(2147483647);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(256)")
.HasMaxLength(256);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContainerId");
b.HasIndex("TenantId", "ContainerId", "Name");
b.ToTable("AbpBlobs");
});
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(128)")
.HasMaxLength(128);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TenantId", "Name");
b.ToTable("AbpBlobContainers");
});
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b =>
{
b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null)
.WithMany()
.HasForeignKey("ContainerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

34
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.cs

@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations
{
public partial class FK_Added : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_ContainerId",
table: "AbpBlobs",
column: "ContainerId");
migrationBuilder.AddForeignKey(
name: "FK_AbpBlobs_AbpBlobContainers_ContainerId",
table: "AbpBlobs",
column: "ContainerId",
principalTable: "AbpBlobContainers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AbpBlobs_AbpBlobContainers_ContainerId",
table: "AbpBlobs");
migrationBuilder.DropIndex(
name: "IX_AbpBlobs_ContainerId",
table: "AbpBlobs");
}
}
}

106
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs

@ -0,0 +1,106 @@
// <auto-generated />
using System;
using BlobStoring.Database.Host.ConsoleApp.ConsoleApp.EfCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.Abp.EntityFrameworkCore;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations
{
[DbContext(typeof(BlobStoringHostDbContext))]
partial class BlobStoringHostDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<Guid>("ContainerId")
.HasColumnType("uniqueidentifier");
b.Property<byte[]>("Content")
.HasColumnType("varbinary(max)")
.HasMaxLength(2147483647);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(256)")
.HasMaxLength(256);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContainerId");
b.HasIndex("TenantId", "ContainerId", "Name");
b.ToTable("AbpBlobs");
});
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(128)")
.HasMaxLength(128);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TenantId", "Name");
b.ToTable("AbpBlobContainers");
});
modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b =>
{
b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null)
.WithMany()
.HasForeignKey("ContainerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

7
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ProfilePictureContainer.cs

@ -0,0 +1,7 @@
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
public class ProfilePictureContainer
{
}
}

51
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Program.cs

@ -0,0 +1,51 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp
{
public class Program
{
public static async Task<int> Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
#if DEBUG
.MinimumLevel.Debug()
#else
.MinimumLevel.Information()
#endif
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Async(c => c.File("Logs/logs.txt"))
.WriteTo.Console()
.CreateLogger();
try
{
Log.Information("Starting console host.");
await CreateHostBuilder(args).RunConsoleAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
internal static IHostBuilder CreateHostBuilder(string[] args) =>
Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<ConsoleAppConsoleAppHostedService>();
});
}
}

5
modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json

@ -0,0 +1,5 @@
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}

4
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/cs.json

@ -1,6 +1,6 @@
{
"culture": "cs",
"texts": {
"ManageYourProfile": "Spravovat profil"
}
}
}

2
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/en.json

@ -1,6 +1,6 @@
{
"culture": "en",
"texts": {
"ManageYourProfile": "Manage your profile"
"ManageYourProfile": "Manage your profile"
}
}

4
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs

@ -27,6 +27,8 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore
b.Property(p => p.Name).IsRequired().HasMaxLength(DatabaseContainerConsts.MaxNameLength);
b.HasMany<DatabaseBlob>().WithOne().HasForeignKey(p => p.ContainerId);
b.HasIndex(x => new {x.TenantId, x.Name});
});
@ -40,6 +42,8 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore
b.Property(p => p.Name).IsRequired().HasMaxLength(DatabaseBlobConsts.MaxNameLength);
b.Property(p => p.Content).HasMaxLength(DatabaseBlobConsts.MaxContentLength);
b.HasOne<DatabaseBlobContainer>().WithMany().HasForeignKey(p => p.ContainerId);
b.HasIndex(x => new {x.TenantId, x.ContainerId, x.Name});
});
}

2
modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/cs.json

@ -11,4 +11,4 @@
"Permission:Create": "Vytvořit",
"Permission:Delete": "Smazat"
}
}
}

6
modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/cs.json

@ -42,6 +42,8 @@
"CreationTime": "Vytvořeno",
"Description": "Popis",
"Blogs": "Blogy",
"Tags": "Tagy"
"Tags": "Tagy",
"ShareOn": "Sdílet na",
"TitleLengthWarning": "Zachovejte velikost titulku pod 60 znaků kvůli SEO!"
}
}
}

7
modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs

@ -19,15 +19,14 @@ namespace Volo.Blogging
private async Task ConfigureMainMenu(MenuConfigurationContext context)
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<BloggingResource>>();
var l = context.GetLocalizer<BloggingResource>();
if (await authorizationService.IsGrantedAsync(BloggingPermissions.Blogs.Management))
if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management))
{
var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"]);
//TODO: Using the same permission. Reconsider.
if (await authorizationService.IsGrantedAsync(BloggingPermissions.Blogs.Management))
if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management))
{
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "/Admin/Blogs"));
}

2
modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json

@ -7,4 +7,4 @@
"CreateYourFirstProject": "Klikněte zde k vytvoření vašeho prvního projektu",
"NoProject": "Žádný projekt!"
}
}
}

9
modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json

@ -6,11 +6,13 @@
"Permission:Edit": "Upravit",
"Permission:Delete": "Smazat",
"Permission:Create": "Vytvořit",
"Permission:Documents": "Dokumenty",
"Menu:DocumentManagement": "Dokumenty",
"Menu:ProjectManagement": "Projekty",
"CreateANewProject": "Vytvořit nový projekt",
"Edit": "Upravit",
"Create": "Vytvořit",
"Pull": "Pull",
"Projects": "Projekty",
"Name": "Název",
"ShortName": "Krátký název",
@ -27,6 +29,9 @@
"DisplayName:LatestVersionBranchName": "Název poslední verze odvětví",
"DisplayName:GitHubRootUrl": "GitHub kořenové URL",
"DisplayName:GitHubAccessToken": "GitHub přístupový token",
"DisplayName:GitHubUserAgent": "GitHub user agent"
"DisplayName:GitHubUserAgent": "GitHub user agent",
"DisplayName:All": "Pull všeho",
"DisplayName:LanguageCode": "Kód jazyka",
"DisplayName:Version": "Verze"
}
}
}

6
modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs

@ -90,6 +90,12 @@ namespace Volo.Docs.Admin.Documents
var documents = new List<Document>();
foreach (var leaf in leafs)
{
if (leaf.Path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
leaf.Path.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var sourceDocument =
await source.GetDocumentAsync(project, leaf.Path, input.LanguageCode, input.Version);
documents.Add(sourceDocument);

6
modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs

@ -19,17 +19,15 @@ namespace Volo.Docs.Admin.Navigation
private async Task ConfigureMainMenu(MenuConfigurationContext context)
{
var administrationMenu = context.Menu.GetAdministration();
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<DocsResource>>();
var l = context.GetLocalizer<DocsResource>();
var rootMenuItem = new ApplicationMenuItem(DocsMenuNames.GroupName, l["Menu:DocumentManagement"], icon: "fa fa-book");
administrationMenu.AddItem(rootMenuItem);
if (await authorizationService.IsGrantedAsync(DocsAdminPermissions.Projects.Default))
if (await context.IsGrantedAsync(DocsAdminPermissions.Projects.Default))
{
rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "/Docs/Admin/Projects"));
}

23
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json

@ -7,15 +7,32 @@
"ShareOn": "Sdílet na",
"Version": "Verze",
"Edit": "Upravit",
"LastEditTime": "Naposled upraveno",
"Delete": "Smazat",
"ClearCache": "Vymazat mezipaměť",
"ClearCacheConfirmationMessage": "Jste si jistí že chcete vymazat veškerou mezipaměť projektu \"{0}\"",
"ReIndexAllProjects": "ReIndexovat všechny projekty",
"ReIndexProject": "ReIndexovat projekt",
"ReIndexProjectConfirmationMessage": "Opravdu reindexovat projekt \"{0}\"",
"SuccessfullyReIndexProject": "Úspěšně reindexován projekt \"{0}\"",
"ReIndexAllProjectConfirmationMessage": "Opravdu reindexovat všechny projekty?",
"SuccessfullyReIndexAllProject": "Úspěšně reindexovány všechny projekty",
"InThisDocument": "V tomto dokumentu",
"GoToTop": "Přejít nahoru",
"Projects": "Projekt(y)",
"NoProjectWarning": "Zatím zde není žádný projekt!",
"DocumentNotFound": "Ups, vyžádaný dokument neexistuje!",
"DocumentNotFound": "Ups, vyžádaný dokument nebyl nalezen!",
"ProjectNotFound": "Ups, vyžádaný projekt nebyl nalezen!",
"NavigationDocumentNotFound": "Tato verze nemá navigační dokument!",
"DocumentNotFoundInSelectedLanguage": "Tento dokument není dostupný ve vybraném jazyce. Zobrazen dokument ve výchozím jazyce.",
"FilterTopics": "Filtrovat témata",
"MultipleVersionDocumentInfo": "Tento dokument má více verzí. Vyberte možnosti, které vám nejlépe vyhovují."
"FullSearch": "Hledat v dokumentech",
"Volo.Docs.Domain:010001": "Elastické vyhledávání není povoleno.",
"MultipleVersionDocumentInfo": "Tento dokument má více verzí. Vyberte možnosti, které vám nejlépe vyhovují.",
"New": "Nové",
"Upd": "Akt",
"NewExplanation": "Vytvořeno v posledních dvou týdnech.",
"UpdatedExplanation": "Aktualizováno v posledních dvou týdnech.",
"Volo.Docs.Domain:010002": "ShortName {ShortName} už existuje."
}
}
}

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json

@ -4,4 +4,4 @@
"Features": "Funkce",
"NoFeatureFoundMessage": "Nejsou zde dostupné žádné funkce."
}
}
}

9
modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json

@ -63,6 +63,8 @@
"Identity.PasswordConfirmationFailed": "Heslo nesouhlasí s potvrzovacím heslem.",
"Identity.StaticRoleRenamingErrorMessage": "Statické role nemohou být přejmenovány.",
"Identity.StaticRoleDeletionErrorMessage": "Statické role nemohou být smazány.",
"Identity.OrganizationUnit.DuplicateDisplayNameWarning": "Organizační jednotka s názvem {0} již existuje. Na stejné úrovni nelze vytvořit více jednotek se stejným názvem.",
"Identity.OrganizationUnit.MaxUserMembershipCount": "Maximální povolený počet členů organizační jednotky pro uživatele",
"Volo.Abp.Identity:010001": "Nemůžete smazat svůj vlastní účet!",
"Permission:IdentityManagement": "Správa identit",
"Permission:RoleManagement": "Správa rolí",
@ -82,6 +84,7 @@
"DisplayName:Abp.Identity.Lockout.LockoutDuration": "Délka blokování (sekundy)",
"DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maximální počet neúspěšných pokusů o přístup",
"DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail": "Požadovat potvrzený email",
"DisplayName:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "Povolit potvrzování telefonního čísla",
"DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Požadovat potvrzené telefonní číslo",
"DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled": "Je povolena změna uživatelského jména",
"DisplayName:Abp.Identity.User.IsEmailUpdateEnabled": "Je povolena změna emailu",
@ -95,8 +98,10 @@
"Description:Abp.Identity.Lockout.LockoutDuration": "Doba, po kterou je uživatel zablokován, když dojde k zablokování.",
"Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Počet neúspěšných pokusů o přístup než je uživatel uzamčen, za předpokladu, že je uzamčení povoleno.",
"Description:Abp.Identity.SignIn.RequireConfirmedEmail": "Zda je k přihlášení vyžadována potvrzená emailová adresa.",
"Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "Zda telefonní číslo může být potvrzeno uživatelem.",
"Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Zda je pro přihlášení vyžadováno potvrzené telefonní číslo.",
"Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Zda může uživatel změnit uživatelské jméno.",
"Description:Abp.Identity.User.IsEmailUpdateEnabled": "Zda může uživatel změnit email."
"Description:Abp.Identity.User.IsEmailUpdateEnabled": "Zda může uživatel změnit email.",
"Volo.Abp.Identity:010002": "Nelze nastavit více než {MaxUserMembershipCount} organizačních jednotek na uživatele!"
}
}
}

11
modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs

@ -16,17 +16,14 @@ namespace Volo.Abp.Identity.Web.Navigation
return;
}
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var hasRolePermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Roles.Default);
var hasUserPermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Users.Default);
var hasRolePermission = await context.IsGrantedAsync(IdentityPermissions.Roles.Default);
var hasUserPermission = await context.IsGrantedAsync(IdentityPermissions.Users.Default);
if (hasRolePermission || hasUserPermission)
{
var administrationMenu = context.Menu.GetAdministration();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<IdentityResource>>();
var l = context.GetLocalizer<IdentityResource>();
var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "fa fa-id-card-o");
administrationMenu.AddItem(identityMenuItem);
@ -43,4 +40,4 @@ namespace Volo.Abp.Identity.Web.Navigation
}
}
}
}
}

8
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json

@ -3,6 +3,10 @@
"texts": {
"Volo.IdentityServer:DuplicateIdentityResourceName": "Název Identity Resource již existuje: {Name}",
"Volo.IdentityServer:DuplicateApiResourceName": "Název Api Resource již existuje: {Name}",
"Volo.IdentityServer:DuplicateClientId": "ClientId již existuje: {ClientId}"
"Volo.IdentityServer:DuplicateClientId": "ClientId již existuje: {ClientId}",
"UserLockedOut": "Tento uživatelský účet byl zablokován kvůli neplatným pokusům o přihlášení. Chvilku počkejte a zkuste to znovu.",
"InvalidUserNameOrPassword": "Neplatné uživatelské jméno či heslo!",
"LoginIsNotAllowed": "Nemáte oprávnění se přihlásit! Musíte potvrdit svůj email/telefonní číslo.",
"InvalidUsername": "Neplatné uživatelské jméno či heslo!"
}
}
}

2
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json

@ -7,4 +7,4 @@
"SelectAllInAllTabs": "Dát veškerá oprávnění",
"SelectAllInThisTab": "Vybrat vše"
}
}
}

2
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json

@ -4,4 +4,4 @@
"Settings": "Nastavení",
"SuccessfullySaved": "Úspěšně uloženo"
}
}
}

2
modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs

@ -29,7 +29,7 @@ namespace Volo.Abp.SettingManagement.Web.Navigation
return;
}
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<AbpSettingManagementResource>>();
var l = context.GetLocalizer<AbpSettingManagementResource>();
context.Menu
.GetAdministration()

6
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json

@ -15,6 +15,8 @@
"Permission:Edit": "Upravit",
"Permission:Delete": "Smazat",
"Permission:ManageConnectionStrings": "Spravovat connection stringy",
"Permission:ManageFeatures": "Spravovat funkce"
"Permission:ManageFeatures": "Spravovat funkce",
"DisplayName:AdminEmailAddress": "Email adresa správce",
"DisplayName:AdminPassword": "Heslo správce"
}
}
}

5
modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs

@ -18,13 +18,12 @@ namespace Volo.Abp.TenantManagement.Web.Navigation
var administrationMenu = context.Menu.GetAdministration();
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<AbpTenantManagementResource>>();
var l = context.GetLocalizer<AbpTenantManagementResource>();
var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, l["Menu:TenantManagement"], icon: "fa fa-users");
administrationMenu.AddItem(tenantManagementMenuItem);
if (await authorizationService.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
if (await context.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
{
tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "/TenantManagement/Tenants"));
}

12
modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/cs.json

@ -1,6 +1,14 @@
{
"culture": "cs",
"texts": {
"VirtualFileExplorer": "Prohlížeč virtuálních souborů",
"VirtualFileType": "Typ virtuálního souborů",
"Menu:VirtualFileExplorer": "Prohlížeč virtuálních souborů",
"LastUpdateTime": "Čas poslední aktualizace",
"VirtualFileName": "Virtuální název souboru",
"FileContent": "Obsah souboru",
"Size": "Velikost",
"BackToRoot": "Zpět na kořen",
"EmptyFileInfoList": "Nejsou žádné virtuální soubory"
}
}
}

2
modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs

@ -15,7 +15,7 @@ namespace Volo.Abp.VirtualFileExplorer.Web.Navigation
return Task.CompletedTask;
}
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<VirtualFileExplorerResource>>();
var l = context.GetLocalizer<VirtualFileExplorerResource>();
context.Menu.Items.Add(new ApplicationMenuItem(VirtualFileExplorerMenuNames.Index, l["Menu:VirtualFileExplorer"], icon: "fa fa-file", url: "/VirtualFileExplorer"));

11
nupkg/common.ps1

@ -18,7 +18,8 @@ $solutions = (
"modules/setting-management",
"modules/tenant-management",
"modules/users",
"modules/virtual-file-explorer"
"modules/virtual-file-explorer",
"modules/blob-storing-database"
)
# List of projects
@ -235,5 +236,11 @@ $projects = (
"modules/users/src/Volo.Abp.Users.MongoDB",
# modules/virtual-file-explorer
"modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web"
"modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web",
# modules/blob-storing-database
"modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain",
"modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared",
"modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore",
"modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB"
)

2
samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/cs.json

@ -7,4 +7,4 @@
"Permission:Delete": "Smazat",
"Permission:Create": "Vytvořit"
}
}
}

3
samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/cs.json

@ -1,6 +1,5 @@
{
"culture": "cs",
"texts": {
}
}
}

2
samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/cs.json

@ -13,4 +13,4 @@
"ImageName": "Název obrázku",
"ProductDeletionWarningMessage": "Opravdu chcete smazat tento produkt?"
}
}
}

8
samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/ProductManagementMenuContributor.cs

@ -19,13 +19,11 @@ namespace ProductManagement
private async Task ConfigureMainMenu(MenuConfigurationContext context)
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<ProductManagementResource>>();
var l = context.GetLocalizer<ProductManagementResource>();
var rootMenuItem = new ApplicationMenuItem("ProductManagement", l["Menu:ProductManagement"]);
if (await authorizationService.IsGrantedAsync(ProductManagementPermissions.Products.Default))
if (await context.IsGrantedAsync(ProductManagementPermissions.Products.Default))
{
rootMenuItem.AddItem(new ApplicationMenuItem("Products", l["Menu:Products"], "/ProductManagement/Products"));
}
@ -33,4 +31,4 @@ namespace ProductManagement
context.Menu.AddItem(rootMenuItem);
}
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save