diff --git a/docs/en/AspNet-Boilerplate-Migration-Guide.md b/docs/en/AspNet-Boilerplate-Migration-Guide.md index d47b266839..39dd01eaa4 100644 --- a/docs/en/AspNet-Boilerplate-Migration-Guide.md +++ b/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(); - var l = context.ServiceProvider - .GetRequiredService>(); + var l = context.GetLocalizer(); 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. \ No newline at end of file +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. diff --git a/docs/en/Customizing-Application-Modules-Overriding-Services.md b/docs/en/Customizing-Application-Modules-Overriding-Services.md index b9890b3aca..ce3729c1ac 100644 --- a/docs/en/Customizing-Application-Modules-Overriding-Services.md +++ b/docs/en/Customizing-Application-Modules-Overriding-Services.md @@ -59,6 +59,7 @@ In most cases, you will want to change one or a few methods of the current imple ### Example: Overriding an Application Service ````csharp +//[RemoteService(IsEnabled = false)] // If you use dynamic controller feature you can disable remote service. Prevent creating duplicate controller for the application service. [Dependency(ReplaceServices = true)] [ExposeServices(typeof(IIdentityUserAppService), typeof(IdentityUserAppService))] public class MyIdentityUserAppService : IdentityUserAppService diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 6adef9b214..77ca49961b 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -303,10 +303,10 @@ TODO:... Volo.Abp.AspNetCore.MultiTenancy package adds following tenant resolvers to determine current tenant from current web request (ordered by priority). These resolvers are added and work out of the box: * **CurrentUserTenantResolveContributor**: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for security**. -* **QueryStringTenantResolver**: Tries to find current tenant id from query string parameter. Parameter name is "__tenant" by default. -* **RouteTenantResolver**: Tries to find current tenant id from route (URL path). Variable name is "__tenant" by default. So, if you defined a route with this variable, then it can determine the current tenant from the route. -* **HeaderTenantResolver**: Tries to find current tenant id from HTTP header. Header name is "__tenant" by default. -* **CookieTenantResolver**: Tries to find current tenant id from cookie values. Cookie name is "__tenant" by default. +* **QueryStringTenantResolveContributor**: Tries to find current tenant id from query string parameter. Parameter name is "__tenant" by default. +* **RouteTenantResolveContributor**: Tries to find current tenant id from route (URL path). Variable name is "__tenant" by default. So, if you defined a route with this variable, then it can determine the current tenant from the route. +* **HeaderTenantResolveContributor**: Tries to find current tenant id from HTTP header. Header name is "__tenant" by default. +* **CookieTenantResolveContributor**: Tries to find current tenant id from cookie values. Cookie name is "__tenant" by default. > If you use nginx as a reverse proxy server, please note that if `TenantKey` contains an underscore or other special characters, there may be a problem, please refer to: http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers @@ -346,7 +346,7 @@ namespace MyCompany.MyProject //Subdomain format: {0}.mydomain.com //Adding as the second highest priority resolver after 'CurrentUserTenantResolveContributor' to //ensure the user cannot impersonate a different tenant. - options.TenantResolvers.Insert(1, new DomainTenantResolver("{0}.mydomain.com")); + options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com")); }); //... @@ -357,7 +357,7 @@ namespace MyCompany.MyProject {0} is the the placeholder to determine current tenant's unique name. -Instead of ``options.TenantResolvers.Insert(1, new DomainTenantResolver("{0}.mydomain.com"));`` you can use this shortcut: +Instead of ``options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com"));`` you can use this shortcut: ````C# options.AddDomainTenantResolver("{0}.mydomain.com"); diff --git a/docs/en/Object-To-Object-Mapping.md b/docs/en/Object-To-Object-Mapping.md index b7463607e9..f5ca805611 100644 --- a/docs/en/Object-To-Object-Mapping.md +++ b/docs/en/Object-To-Object-Mapping.md @@ -162,6 +162,61 @@ public class MyProfile : Profile It is suggested to use the `MapExtraProperties()` method if both classes are extensible objects (implement the `IHasExtraProperties` interface). See the [object extension document](Object-Extensions.md) for more. +### Other Useful Extension Methods + +There are some more extension methods those can simplify your mapping code. + +#### Ignoring Audit Properties + +It is common to ignore audit properties when you map an object to another. + +Assume that you need to map a `ProductDto` ([DTO](Data-Transfer-Objects.md)) to a `Product` [entity](Entities.md) and the entity is inheriting from the `AuditedEntity` class (which provides properties like `CreationTime`, `CreatorId`, `IHasModificationTime`... etc). + +You probably want to ignore these base properties while mapping from the DTO. You can use `IgnoreAuditedObjectProperties()` method to ignore all audit properties (instead of manually ignoring them one by one): + +````csharp +public class MyProfile : Profile +{ + public MyProfile() + { + CreateMap() + .IgnoreAuditedObjectProperties(); + } +} +```` + +There are more extension methods like `IgnoreFullAuditedObjectProperties()` and `IgnoreCreationAuditedObjectProperties()` those can be used based on your entity type. + +> See the "*Base Classes & Interfaces for Audit Properties*" section in the [entities document](Entities.md) to know more about auditing properties. + +#### Ignoring Other Properties + +In AutoMapper, you typically write such a mapping code to ignore a property: + +````csharp +public class MyProfile : Profile +{ + public MyProfile() + { + CreateMap() + .ForMember(x => x.CreationTime, map => map.Ignore()); + } +} +```` + +We found it unnecessarily long and created the `Ignore()` extension method: + +````csharp +public class MyProfile : Profile +{ + public MyProfile() + { + CreateMap() + .Ignore(x => x.CreationTime); + } +} +```` + ## Advanced Topics ### IObjectMapper Interface diff --git a/docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md b/docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md index 94a2120059..cf40590d61 100644 --- a/docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md +++ b/docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md @@ -59,6 +59,7 @@ context.Services.Replace( ### 示例: 重写服务方法 ````csharp +//[RemoteService(IsEnabled = false)] // 如果你在使用动态控制器,为了避免为应用服务创建重复的控制器, 你可以禁用远程访问. [Dependency(ReplaceServices = true)] [ExposeServices(typeof(IIdentityUserAppService), typeof(IdentityUserAppService))] public class MyIdentityUserAppService : IdentityUserAppService diff --git a/docs/zh-Hans/Multi-Tenancy.md b/docs/zh-Hans/Multi-Tenancy.md index 49cf358205..3e65a97cef 100644 --- a/docs/zh-Hans/Multi-Tenancy.md +++ b/docs/zh-Hans/Multi-Tenancy.md @@ -304,10 +304,10 @@ TODO:... Volo.Abp.AspNetCore.MultiTenancy 添加了下面这些租户解析器,从当前Web请求(按优先级排序)中确定当前租户. * **CurrentUserTenantResolveContributor**: 如果当前用户已登录,从当前用户的声明中获取租户Id. **出于安全考虑,应该始终将其做为第一个Contributor**. -* **QueryStringTenantResolver**: 尝试从query string参数中获取当前租户,默认参数名为"__tenant". -* **RouteTenantResolver**:尝试从当前路由中获取(URL路径),默认是变量名是"__tenant".所以,如果你的路由中定义了这个变量,就可以从路由中确定当前租户. -* **HeaderTenantResolver**: 尝试从HTTP header中获取当前租户,默认的header名称是"__tenant". -* **CookieTenantResolver**: 尝试从当前cookie中获取当前租户.默认的Cookie名称是"__tenant". +* **QueryStringTenantResolveContributor**: 尝试从query string参数中获取当前租户,默认参数名为"__tenant". +* **RouteTenantResolveContributor**:尝试从当前路由中获取(URL路径),默认是变量名是"__tenant".所以,如果你的路由中定义了这个变量,就可以从路由中确定当前租户. +* **HeaderTenantResolveContributor**: 尝试从HTTP header中获取当前租户,默认的header名称是"__tenant". +* **CookieTenantResolveContributor**: 尝试从当前cookie中获取当前租户.默认的Cookie名称是"__tenant". > 如果你使用nginx作为反向代理服务器,请注意如果`TenantKey`包含下划线或其他特殊字符可能存在问题, 请参考: http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers @@ -344,7 +344,7 @@ namespace MyCompany.MyProject Configure(options => { //子域名格式: {0}.mydomain.com (作为第二优先级解析器添加, 位于CurrentUserTenantResolveContributor之后) - options.TenantResolvers.Insert(1, new DomainTenantResolver("{0}.mydomain.com")); + options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com")); }); //... @@ -355,7 +355,7 @@ namespace MyCompany.MyProject {0}是用来确定当前租户唯一名称的占位符. -你可以使用下面的方法,代替``options.TenantResolvers.Insert(1, new DomainTenantResolver("{0}.mydomain.com"));``: +你可以使用下面的方法,代替``options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com"));``: ````C# options.AddDomainTenantResolver("{0}.mydomain.com"); diff --git a/docs/zh-Hans/SignalR-Integration.md b/docs/zh-Hans/SignalR-Integration.md index 8045bbd394..3dea373f5a 100644 --- a/docs/zh-Hans/SignalR-Integration.md +++ b/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) \ No newline at end of file +![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) \ No newline at end of file diff --git a/docs/zh-Hans/Tutorials/Part-1.md b/docs/zh-Hans/Tutorials/Part-1.md index 9589c430b6..5ee6b31e08 100644 --- a/docs/zh-Hans/Tutorials/Part-1.md +++ b/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). diff --git a/docs/zh-Hans/Tutorials/Part-2.md b/docs/zh-Hans/Tutorials/Part-2.md index 5e73c753e6..8dd64a49d0 100644 --- a/docs/zh-Hans/Tutorials/Part-2.md +++ b/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` 文件,使用以下内容替换 `` 标签: @@ -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}} diff --git a/docs/zh-Hans/UI/Angular/Component-Replacement.md b/docs/zh-Hans/UI/Angular/Component-Replacement.md index dc7c1a33c4..4465f34893 100644 --- a/docs/zh-Hans/UI/Angular/Component-Replacement.md +++ b/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 ``` -打开 `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: ` + + + logo + + `, +}) +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 + +``` + +打开 `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; + + @Select(ConfigState.getDeep('localization.languages')) + languages$: Observable; + + smallScreen = window.innerWidth < 992; + + get defaultLanguage$(): Observable { + return this.languages$.pipe( + map( + languages => + snq( + () => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName, + ), + '', + ), + ); + } + + get dropdownLanguages$(): Observable { + 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 + +``` + +打开 `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) \ No newline at end of file diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index d798580a25..23b17c1231 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -454,6 +454,15 @@ } ] }, + { + "text": "实时", + "items": [ + { + "text": "SignalR集成", + "path": "SignalR-Integration.md" + } + ] + }, { "text": "后台服务", "items": [ diff --git a/docs/zh-Hans/images/hello-template.png b/docs/zh-Hans/images/hello-template.png new file mode 100644 index 0000000000..0a3ce2816a Binary files /dev/null and b/docs/zh-Hans/images/hello-template.png differ diff --git a/docs/zh-Hans/images/multiple-file-template.png b/docs/zh-Hans/images/multiple-file-template.png new file mode 100644 index 0000000000..a2e7327301 Binary files /dev/null and b/docs/zh-Hans/images/multiple-file-template.png differ diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelper.cs index 632bbd3a92..1188d68056 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelper.cs +++ b/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 : AbpTagHelper where TTagHelper : AbpTagHelper - where TService : class, IAbpTagHelperService + where TService : class, IAbpTagHelperService { 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); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs index 141d995fd7..d710793151 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs +++ b/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; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index 16a700f4bc..efd3af2d2c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/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) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs index c299826a07..51982ae4eb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs +++ b/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 AspItems { get; set; } - [HtmlAttributeNotBound] - [ViewContext] - public ViewContext ViewContext { get; set; } - public AbpRadioInputTagHelper(AbpRadioInputTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs index ae46336f77..4df9733d83 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs +++ b/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) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelper.cs index 2e6f7cd743..8132623d00 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelper.cs +++ b/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) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelper.cs index ea9980e183..170c16c571 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelper.cs +++ b/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 : AbpTagHelper, IBundleItemTagHelper + public abstract class AbpBundleItemTagHelper : AbpTagHelper, IBundleItemTagHelper where TTagHelper : AbpTagHelper, IBundleItemTagHelper - where TTagHelperService: AbpBundleItemTagHelperService + where TTagHelperService: AbpBundleItemTagHelperService { /// /// A file path. @@ -57,4 +57,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers protected abstract string GetFileExtension(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs index fc59051720..eca80c5fcf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs +++ b/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 : AbpTagHelperService - where TTagHelper : TagHelper, IBundleItemTagHelper + public abstract class AbpBundleItemTagHelperService : AbpTagHelperService + where TTagHelper : AbpTagHelper, IBundleItemTagHelper + where TService : class, IAbpTagHelperService { 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 @@ -37,4 +39,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs index a8eadce1e8..f0c76d5cc4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs +++ b/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 : AbpTagHelperService - where TTagHelper : TagHelper, IBundleTagHelper + public abstract class AbpBundleTagHelperService : AbpTagHelperService + where TTagHelper : AbpTagHelper, IBundleTagHelper + where TService : class, IAbpTagHelperService { 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; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptBundleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptBundleTagHelperService.cs index c4b00b39cd..be6b7273e4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptBundleTagHelperService.cs +++ b/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 + public class AbpScriptBundleTagHelperService : AbpBundleTagHelperService { - public AbpScriptBundleTagHelperService(AbpTagHelperScriptService resourceHelper) + public AbpScriptBundleTagHelperService(AbpTagHelperScriptService resourceHelper) : base(resourceHelper) { } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptTagHelperService.cs index d31c7bd7ce..6321bfdc6c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpScriptTagHelperService.cs +++ b/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 + public class AbpScriptTagHelperService : AbpBundleItemTagHelperService { public AbpScriptTagHelperService(AbpTagHelperScriptService resourceService) : base(resourceService) { } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleBundleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleBundleTagHelperService.cs index f52f3dac88..7d05e3a96c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleBundleTagHelperService.cs +++ b/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 + public class AbpStyleBundleTagHelperService : AbpBundleTagHelperService { - public AbpStyleBundleTagHelperService(AbpTagHelperStyleService resourceHelper) + public AbpStyleBundleTagHelperService(AbpTagHelperStyleService resourceHelper) : base(resourceHelper) { } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleTagHelperService.cs index bb828e47ae..7854e5157e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpStyleTagHelperService.cs +++ b/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 + public class AbpStyleTagHelperService : AbpBundleItemTagHelperService { public AbpStyleTagHelperService(AbpTagHelperStyleService resourceService) : base(resourceService) { } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs index 88387e8937..2971716b90 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs +++ b/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 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> 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 bundleItems) { return bundleItems.JoinAsString("|").ToMd5(); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs index b087db517f..6efbb793e7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs +++ b/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($"{Environment.NewLine}"); + output.Content.AppendHtml($"{Environment.NewLine}"); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs index 2d273345cb..8612e4f8b4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs +++ b/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($"{Environment.NewLine}"); + output.Content.AppendHtml($"{Environment.NewLine}"); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj index 2400b9c291..906f4fc2c9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj @@ -18,10 +18,8 @@ - - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json index 5887243cb4..05457dfa16 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml index 0c6b5d8a3b..064a3756c4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml @@ -5,12 +5,13 @@ var elementId = string.IsNullOrEmpty(menuItem.ElementId) ? string.Empty : $"id=\"{menuItem.ElementId}\""; var cssClass = string.IsNullOrEmpty(menuItem.CssClass) ? string.Empty : menuItem.CssClass; var disabled = menuItem.IsDisabled ? "disabled" : string.Empty; + var url = string.IsNullOrEmpty(menuItem.Url) ? "#" : Url.Content(menuItem.Url); if (menuItem.IsLeaf) { if (menuItem.Url != null) { } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml index eaec9fc7c4..108de2306a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml @@ -4,12 +4,13 @@ var elementId = string.IsNullOrEmpty(Model.ElementId) ? string.Empty : $"id=\"{Model.ElementId}\""; var cssClass = string.IsNullOrEmpty(Model.CssClass) ? string.Empty : Model.CssClass; var disabled = Model.IsDisabled ? "disabled" : string.Empty; + var url = string.IsNullOrEmpty(Model.Url) ? "#" : Url.Content(Model.Url); } @if (Model.IsLeaf) { if (Model.Url != null) { - + @if (Model.Icon != null) { if (Model.Icon.StartsWith("fa")) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml index 65ca8d940e..8b7ea1bf2c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml @@ -12,7 +12,7 @@ diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml index d1738165d3..06a96edce7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml @@ -27,8 +27,9 @@ var elementId = string.IsNullOrEmpty(menuItem.ElementId) ? string.Empty : $"id=\"{menuItem.ElementId}\""; var cssClass = string.IsNullOrEmpty(menuItem.CssClass) ? string.Empty : menuItem.CssClass; var disabled = menuItem.IsDisabled ? "disabled" : string.Empty; + var url = string.IsNullOrEmpty(menuItem.Url) ? "#" : Url.Content(menuItem.Url); - + @if (menuItem.Icon != null) { if (menuItem.Icon.StartsWith("fa")) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj index 43f5bc20bf..c390cfe58c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj @@ -17,17 +17,11 @@ - - - - - - @@ -36,5 +30,5 @@ - + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj index 66015b14a7..078563ace3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj @@ -17,11 +17,6 @@ - - - - - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponent.cs new file mode 100644 index 0000000000..32a89cdcb8 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponent.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpApplicationPath +{ + public class AbpApplicationPathViewComponent : AbpViewComponent + { + public IViewComponentResult Invoke() + { + var applicationPath = ViewContext.HttpContext.Request.PathBase.Value; + var model = new AbpApplicationPathViewComponentModel + { + ApplicationPath = applicationPath == null ? "/" : applicationPath.EnsureEndsWith('/') + }; + + return View("~/Pages/Shared/Components/AbpApplicationPath/Default.cshtml",model); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponentModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponentModel.cs new file mode 100644 index 0000000000..ecf50f63e8 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/AbpApplicationPathViewComponentModel.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpApplicationPath +{ + public class AbpApplicationPathViewComponentModel + { + public string ApplicationPath { get; set; } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/Default.cshtml new file mode 100644 index 0000000000..a9a9b1fa86 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpApplicationPath/Default.cshtml @@ -0,0 +1,4 @@ +@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpApplicationPath.AbpApplicationPathViewComponentModel + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj index 7c4147bba5..71e1257a4d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj @@ -18,16 +18,10 @@ - - - - - - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 90e72d3e49..beef0d1f0c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/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, diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj index 06afcf3f3e..9d0f384611 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj @@ -17,9 +17,4 @@ - - - - - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj index ffdaf02d94..d14d639fbb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj @@ -14,11 +14,6 @@ - - - - - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/ViewFeatures/ViewContextExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Mvc/ViewFeatures/ViewContextExtensions.cs new file mode 100644 index 0000000000..6f09b5bb50 --- /dev/null +++ b/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(); + return urlHelperFactory.GetUrlHelper(viewContext); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpMvcBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpMvcBuilderExtensions.cs index 77b517bc45..c7f3777466 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpMvcBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpMvcBuilderExtensions.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; @@ -8,13 +9,23 @@ namespace Microsoft.Extensions.DependencyInjection { public static void AddApplicationPartIfNotExists(this IMvcBuilder mvcBuilder, Assembly assembly) { - if (mvcBuilder.PartManager.ApplicationParts.Any( + mvcBuilder.PartManager.ApplicationParts.AddIfNotContains(assembly); + } + + public static void AddApplicationPartIfNotExists(this IMvcCoreBuilder mvcCoreBuilder, Assembly assembly) + { + mvcCoreBuilder.PartManager.ApplicationParts.AddIfNotContains(assembly); + } + + public static void AddIfNotContains(this IList applicationParts, Assembly assembly) + { + if (applicationParts.Any( p => p is AssemblyPart assemblyPart && assemblyPart.Assembly == assembly)) { return; } - mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(assembly)); + applicationParts.Add(new AssemblyPart(assembly)); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 6785cb710b..263178e0ed 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Reflection; @@ -75,14 +76,14 @@ namespace Volo.Abp.AspNetCore.Mvc (int) HttpStatusCode.NotImplemented, (int) HttpStatusCode.InternalServerError }; - + options.SupportedResponseTypes.AddIfNotContains(statusCodes.Select(statusCode => new ApiResponseType { Type = typeof(RemoteServiceErrorResponse), StatusCode = statusCode })); }); - + context.Services.PostConfigure(options => { if (options.MinifyGeneratedScript == null) @@ -126,10 +127,10 @@ namespace Volo.Abp.AspNetCore.Mvc return factory.Create(resourceType); } - return factory.CreateDefaultOrNull() ?? + return factory.CreateDefaultOrNull() ?? factory.Create(type); }; - }) + }) .AddViewLocalization(); //TODO: How to configure from the application? Also, consider to move to a UI module since APIs does not care about it. Configure(options => @@ -161,7 +162,7 @@ namespace Volo.Abp.AspNetCore.Mvc var application = context.Services.GetSingletonInstance(); partManager.FeatureProviders.Add(new AbpConventionalControllerFeatureProvider(application)); - partManager.ApplicationParts.Add(new AssemblyPart(typeof(AbpAspNetCoreMvcModule).Assembly)); + partManager.ApplicationParts.AddIfNotContains(typeof(AbpAspNetCoreMvcModule).Assembly); Configure(mvcOptions => { @@ -179,6 +180,14 @@ namespace Volo.Abp.AspNetCore.Mvc }); } + public override void PostConfigureServices(ServiceConfigurationContext context) + { + ApplicationPartSorter.Sort( + context.Services.GetSingletonInstance(), + context.Services.GetSingletonInstance() + ); + } + public override void OnApplicationInitialization(ApplicationInitializationContext context) { AddApplicationParts(context); @@ -220,12 +229,7 @@ namespace Volo.Abp.AspNetCore.Mvc { foreach (var moduleAssembly in moduleAssemblies) { - if (partManager.ApplicationParts.OfType().Any(p => p.Assembly == moduleAssembly)) - { - continue; - } - - partManager.ApplicationParts.Add(new AssemblyPart(moduleAssembly)); + partManager.ApplicationParts.AddIfNotContains(moduleAssembly); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs new file mode 100644 index 0000000000..85fc13c840 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc +{ + /// + /// This class is used to align order of the MVC Application Parts with the order of + /// ABP module dependencies. + /// + public static class ApplicationPartSorter + { + public static void Sort(ApplicationPartManager partManager, IModuleContainer moduleContainer) + { + /* Performing a double Reverse() to preserve the original order for non-sorted parts + */ + + var dependencyDictionary = CreateDependencyDictionary(partManager, moduleContainer); + + var sortedParts = partManager + .ApplicationParts + .Reverse() //First Revers + .SortByDependencies(p => dependencyDictionary[p]); + + sortedParts.Reverse(); //Reverse again + + //Replace the original parts with the sorted parts + partManager.ApplicationParts.Clear(); + foreach (var applicationPart in sortedParts) + { + partManager.ApplicationParts.Add(applicationPart); + } + } + + private static Dictionary> CreateDependencyDictionary( + ApplicationPartManager partManager, IModuleContainer moduleContainer) + { + var dependencyDictionary = new Dictionary>(); + + foreach (var applicationPart in partManager.ApplicationParts) + { + dependencyDictionary[applicationPart] = + CreateDependencyList(applicationPart, partManager, moduleContainer); + } + + return dependencyDictionary; + } + + private static List CreateDependencyList( + ApplicationPart applicationPart, + ApplicationPartManager partManager, + IModuleContainer moduleContainer) + { + var list = new List(); + + if (applicationPart is AssemblyPart assemblyPart) + { + AddDependencies(list, assemblyPart, partManager, moduleContainer); + } + else if (applicationPart is CompiledRazorAssemblyPart compiledRazorAssemblyPart) + { + AddDependencies(list, compiledRazorAssemblyPart, partManager, moduleContainer); + } + + return list; + } + + private static void AddDependencies( + List list, + AssemblyPart assemblyPart, + ApplicationPartManager partManager, + IModuleContainer moduleContainer) + { + var dependedAssemblyParts = GetDependedAssemblyParts( + partManager, + moduleContainer, + assemblyPart + ); + + list.AddRange(dependedAssemblyParts); + + foreach (var dependedAssemblyPart in dependedAssemblyParts) + { + var viewsPart = GetViewsPartOrNull(partManager, dependedAssemblyPart); + if (viewsPart != null) + { + list.Add(viewsPart); + } + } + } + + private static void AddDependencies( + List list, + CompiledRazorAssemblyPart compiledRazorAssemblyPart, + ApplicationPartManager partManager, + IModuleContainer moduleContainer) + { + if (!compiledRazorAssemblyPart.Name.EndsWith(".Views")) + { + return; + } + + var originalAssemblyPart = GetOriginalAssemblyPartOrNull(compiledRazorAssemblyPart, partManager); + if (originalAssemblyPart == null) + { + return; + } + + list.Add(originalAssemblyPart); + } + + private static AssemblyPart[] GetDependedAssemblyParts( + ApplicationPartManager partManager, + IModuleContainer moduleContainer, + AssemblyPart assemblyPart) + { + var moduleDescriptor = GetModuleDescriptorForAssemblyOrNull(moduleContainer, assemblyPart.Assembly); + if (moduleDescriptor == null) + { + return Array.Empty(); + } + + var moduleDependedAssemblies = moduleDescriptor + .Dependencies + .Select(d => d.Assembly) + .ToArray(); + + return partManager.ApplicationParts + .OfType() + .Where(a => a.Assembly.IsIn(moduleDependedAssemblies)) + .Distinct() + .ToArray(); + } + + private static CompiledRazorAssemblyPart GetViewsPartOrNull(ApplicationPartManager partManager, + ApplicationPart assemblyPart) + { + var viewsAssemblyName = assemblyPart.Name + ".Views"; + return partManager + .ApplicationParts + .OfType() + .FirstOrDefault(p => p.Name == viewsAssemblyName); + } + + private static AssemblyPart GetOriginalAssemblyPartOrNull( + CompiledRazorAssemblyPart compiledRazorAssemblyPart, + ApplicationPartManager partManager) + { + var originalAssemblyName = compiledRazorAssemblyPart.Name.RemovePostFix(".Views"); + return partManager.ApplicationParts + .OfType() + .FirstOrDefault(p => p.Name == originalAssemblyName); + } + + private static IAbpModuleDescriptor GetModuleDescriptorForAssemblyOrNull( + IModuleContainer moduleContainer, + Assembly assembly) + { + return moduleContainer + .Modules + .FirstOrDefault(m => m.Assembly == assembly); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs index 36e0bebfd6..15854e10a6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs @@ -86,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authentication protected virtual string GetAppHomeUrl() { - return "/"; + return "~/"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs index 3f25eb2f84..06b9c9a620 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs @@ -32,14 +32,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization return Redirect(GetRedirectUrl(returnUrl)); } - return Redirect("/"); + return Redirect("~/"); } private string GetRedirectUrl(string returnUrl) { if (returnUrl.IsNullOrEmpty()) { - return "/"; + return "~/"; } if (Url.IsLocalUrl(returnUrl)) @@ -47,7 +47,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization return returnUrl; } - return "/"; + return "~/"; } } } diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index 40be84cb6f..d26ec97bf2 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Volo.Abp.AutoMapper; using Volo.Abp.Data; using Volo.Abp.ObjectExtending; @@ -35,5 +36,13 @@ namespace AutoMapper }) ); } + + public static IMappingExpression IgnoreExtraProperties( + this IMappingExpression mappingExpression) + where TDestination : IHasExtraProperties + where TSource : IHasExtraProperties + { + return mappingExpression.Ignore(x => x.ExtraProperties); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj index 327f2078d1..2fb39be54f 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj +++ b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs index 1590e879b1..214872e371 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs @@ -2,6 +2,7 @@ using AutoMapper; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.Auditing; using Volo.Abp.Modularity; using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectMapping; @@ -10,7 +11,9 @@ namespace Volo.Abp.AutoMapper { [DependsOn( typeof(AbpObjectMappingModule), - typeof(AbpObjectExtendingModule))] + typeof(AbpObjectExtendingModule), + typeof(AbpAuditingModule) + )] public class AbpAutoMapperModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions.cs index d8cc559d0f..3a2094d68c 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Linq.Expressions; using AutoMapper; +using Volo.Abp.Auditing; namespace Volo.Abp.AutoMapper { @@ -10,5 +11,141 @@ namespace Volo.Abp.AutoMapper { return mappingExpression.ForMember(destinationMember, opts => opts.Ignore()); } + + public static IMappingExpression IgnoreHasCreationTimeProperties( + this IMappingExpression mappingExpression) + where TDestination : IHasCreationTime + { + return mappingExpression.Ignore(x => x.CreationTime); + } + + public static IMappingExpression IgnoreMayHaveCreatorProperties( + this IMappingExpression mappingExpression) + where TDestination : IMayHaveCreator + { + return mappingExpression.Ignore(x => x.CreatorId); + } + + public static IMappingExpression IgnoreCreationAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : ICreationAuditedObject + { + return mappingExpression + .IgnoreHasCreationTimeProperties() + .IgnoreMayHaveCreatorProperties(); + } + + public static IMappingExpression IgnoreHasModificationTimeProperties( + this IMappingExpression mappingExpression) + where TDestination : IHasModificationTime + { + return mappingExpression.Ignore(x => x.LastModificationTime); + } + + public static IMappingExpression IgnoreModificationAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IModificationAuditedObject + { + return mappingExpression + .IgnoreHasModificationTimeProperties() + .Ignore(x => x.LastModifierId); + } + + public static IMappingExpression IgnoreAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IAuditedObject + { + return mappingExpression + .IgnoreCreationAuditedObjectProperties() + .IgnoreModificationAuditedObjectProperties(); + } + + public static IMappingExpression IgnoreSoftDeleteProperties( + this IMappingExpression mappingExpression) + where TDestination : ISoftDelete + { + return mappingExpression.Ignore(x => x.IsDeleted); + } + + public static IMappingExpression IgnoreHasDeletionTimeProperties( + this IMappingExpression mappingExpression) + where TDestination : IHasDeletionTime + { + return mappingExpression + .IgnoreSoftDeleteProperties() + .Ignore(x => x.DeletionTime); + } + + public static IMappingExpression IgnoreDeletionAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IDeletionAuditedObject + { + return mappingExpression + .IgnoreHasDeletionTimeProperties() + .Ignore(x => x.DeleterId); + } + + public static IMappingExpression IgnoreFullAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IFullAuditedObject + { + return mappingExpression + .IgnoreAuditedObjectProperties() + .IgnoreDeletionAuditedObjectProperties(); + } + + public static IMappingExpression IgnoreMayHaveCreatorProperties( + this IMappingExpression mappingExpression) + where TDestination : IMayHaveCreator + { + return mappingExpression + .Ignore(x => x.Creator); + } + + public static IMappingExpression IgnoreCreationAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : ICreationAuditedObject + { + return mappingExpression + .IgnoreCreationAuditedObjectProperties() + .IgnoreMayHaveCreatorProperties(); + } + + public static IMappingExpression IgnoreModificationAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IModificationAuditedObject + { + return mappingExpression + .IgnoreModificationAuditedObjectProperties() + .Ignore(x => x.LastModifier); + } + + public static IMappingExpression IgnoreAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IAuditedObject + { + return mappingExpression + .IgnoreCreationAuditedObjectProperties() + .IgnoreModificationAuditedObjectProperties(); + } + + public static IMappingExpression IgnoreDeletionAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IDeletionAuditedObject + { + return mappingExpression + .IgnoreDeletionAuditedObjectProperties() + .Ignore(x => x.Deleter); + } + + + public static IMappingExpression IgnoreFullAuditedObjectProperties( + this IMappingExpression mappingExpression) + where TDestination : IFullAuditedObject + { + return mappingExpression + .IgnoreAuditedObjectProperties() + .IgnoreDeletionAuditedObjectProperties(); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmGlobalPackagesChecker.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmGlobalPackagesChecker.cs index 59c262e065..7c8ba63e29 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmGlobalPackagesChecker.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmGlobalPackagesChecker.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.Cli.ProjectModification protected virtual string GetInstalledNpmPackages() { Logger.LogInformation("Checking installed npm global packages..."); - return CmdHelper.RunCmdAndGetOutput("npm list -g --depth 0"); + return CmdHelper.RunCmdAndGetOutput("npm list -g --depth 0 --silent"); } protected virtual void InstallYarn() diff --git a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs index a123236a4e..ec7a640a39 100644 --- a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs @@ -180,7 +180,10 @@ namespace System.Collections.Generic /// The type of the members of values. /// A list of objects to sort /// Function to resolve the dependencies - /// + /// + /// Returns a new list ordered by dependencies. + /// If A depends on B, then B will come before than A in the resulting list. + /// public static List SortByDependencies(this IEnumerable source, Func> getDependencies) { /* See: http://www.codeproject.com/Articles/869059/Topological-sorting-in-Csharp diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index 8036760f6a..1e5b251ca0 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; @@ -42,6 +43,7 @@ namespace Volo.Abp services.AddCoreAbpServices(this, options); Modules = LoadModules(services, options); + ConfigureServices(); } public virtual void Shutdown() @@ -75,7 +77,7 @@ namespace Volo.Abp } } - private IReadOnlyList LoadModules(IServiceCollection services, AbpApplicationCreationOptions options) + protected virtual IReadOnlyList LoadModules(IServiceCollection services, AbpApplicationCreationOptions options) { return services .GetSingletonInstance() @@ -85,5 +87,75 @@ namespace Volo.Abp options.PlugInSources ); } + + //TODO: We can extract a new class for this + protected virtual void ConfigureServices() + { + var context = new ServiceConfigurationContext(Services); + Services.AddSingleton(context); + + foreach (var module in Modules) + { + if (module.Instance is AbpModule abpModule) + { + abpModule.ServiceConfigurationContext = context; + } + } + + //PreConfigureServices + foreach (var module in Modules.Where(m => m.Instance is IPreConfigureServices)) + { + try + { + ((IPreConfigureServices)module.Instance).PreConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IPreConfigureServices.PreConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } + } + + //ConfigureServices + foreach (var module in Modules) + { + if (module.Instance is AbpModule abpModule) + { + if (!abpModule.SkipAutoServiceRegistration) + { + Services.AddAssembly(module.Type.Assembly); + } + } + + try + { + module.Instance.ConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IAbpModule.ConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } + } + + //PostConfigureServices + foreach (var module in Modules.Where(m => m.Instance is IPostConfigureServices)) + { + try + { + ((IPostConfigureServices)module.Instance).PostConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IPostConfigureServices.PostConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } + } + + foreach (var module in Modules) + { + if (module.Instance is AbpModule abpModule) + { + abpModule.ServiceConfigurationContext = null; + } + } + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs index 374e1adb78..7e7e69d457 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs @@ -20,7 +20,6 @@ namespace Volo.Abp.Modularity var modules = GetDescriptors(services, startupModuleType, plugInSources); modules = SortByDependency(modules, startupModuleType); - ConfigureServices(modules, services); return modules.ToArray(); } @@ -89,75 +88,6 @@ namespace Volo.Abp.Modularity return module; } - protected virtual void ConfigureServices(List modules, IServiceCollection services) - { - var context = new ServiceConfigurationContext(services); - services.AddSingleton(context); - - foreach (var module in modules) - { - if (module.Instance is AbpModule abpModule) - { - abpModule.ServiceConfigurationContext = context; - } - } - - //PreConfigureServices - foreach (var module in modules.Where(m => m.Instance is IPreConfigureServices)) - { - try - { - ((IPreConfigureServices)module.Instance).PreConfigureServices(context); - } - catch (Exception ex) - { - throw new AbpInitializationException($"An error occurred during {nameof(IPreConfigureServices.PreConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); - } - } - - //ConfigureServices - foreach (var module in modules) - { - if (module.Instance is AbpModule abpModule) - { - if (!abpModule.SkipAutoServiceRegistration) - { - services.AddAssembly(module.Type.Assembly); - } - } - - try - { - module.Instance.ConfigureServices(context); - } - catch (Exception ex) - { - throw new AbpInitializationException($"An error occurred during {nameof(IAbpModule.ConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); - } - } - - //PostConfigureServices - foreach (var module in modules.Where(m => m.Instance is IPostConfigureServices)) - { - try - { - ((IPostConfigureServices)module.Instance).PostConfigureServices(context); - } - catch (Exception ex) - { - throw new AbpInitializationException($"An error occurred during {nameof(IPostConfigureServices.PostConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); - } - } - - foreach (var module in modules) - { - if (module.Instance is AbpModule abpModule) - { - abpModule.ServiceConfigurationContext = null; - } - } - } - protected virtual void SetDependencies(List modules, AbpModuleDescriptor module) { foreach (var dependedModuleType in AbpModuleHelper.FindDependedModuleTypes(module.Type)) diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/cs.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/cs.json new file mode 100644 index 0000000000..cfe5995a67 --- /dev/null +++ b/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ů." + } +} diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json index c4b1aaad40..12a4b89b13 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json +++ b/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" } } - \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs index 2e8eb41844..a9b51eca6a 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs +++ b/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 FindActionAsync(string baseUrl, Type serviceType, MethodInfo method) + public async Task 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 GetApiDescriptionAsync(string baseUrl) + public virtual async Task GetApiDescriptionAsync(HttpClient client, string baseUrl) { - return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl)); + return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(client, baseUrl)); } - protected virtual async Task GetApiDescriptionFromServerAsync(string baseUrl) + protected virtual async Task 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) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index 031ea7d99b..533b76aa6c 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/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 MakeRequestAndGetResultAsync(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; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs index 010d55706e..e957752330 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs +++ b/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 FindActionAsync(string baseUrl, Type serviceType, MethodInfo invocationMethod); + Task FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo invocationMethod); - Task GetApiDescriptionAsync(string baseUrl); + Task GetApiDescriptionAsync(HttpClient client, string baseUrl); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json index bea8d0379b..2b9ef7890f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json +++ b/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." } } diff --git a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/cs.json b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/cs.json new file mode 100644 index 0000000000..e8782abe99 --- /dev/null +++ b/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" + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index d4960c883e..4400fe7b46 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -101,7 +102,7 @@ namespace Volo.Abp.UI.Navigation Name = name; DisplayName = displayName; - Url = url; + Url = url?.EnsureStartsWith('~'); Icon = icon; Order = order; CustomData = customData; @@ -133,4 +134,4 @@ namespace Volo.Abp.UI.Navigation return $"[ApplicationMenuItem] Name = {Name}"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json index b2c46465c0..987afffef5 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/cs.json @@ -3,4 +3,4 @@ "texts": { "Menu:Administration": "Administrace" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index 3fba79a2b3..b457790e08 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json index e3a0453e08..dce07f8c91 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json +++ b/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é." } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/cs.json b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/cs.json index 65c0603c50..f4ee60bf77 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions_Tests.cs new file mode 100644 index 0000000000..f97450a749 --- /dev/null +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperExpressionExtensions_Tests.cs @@ -0,0 +1,177 @@ +using System; +using AutoMapper; +using Shouldly; +using Volo.Abp.Auditing; +using Xunit; + +namespace Volo.Abp.AutoMapper +{ + public class AutoMapperExpressionExtensions_Tests + { + [Fact] + public void Should_Ignore_Configured_Property() + { + var mapper = CreateMapper( + cfg => cfg + .CreateMap() + .Ignore(x => x.Value2) + .Ignore(x => x.Value3) + ); + + var obj2 = mapper.Map( + new SimpleClass1 + { + Value1 = "v1", + Value2 = "v2" + } + ); + + obj2.Value1.ShouldBe("v1"); + obj2.Value2.ShouldBeNull(); + obj2.Value3.ShouldBeNull(); + } + + [Fact] + public void Should_Ignore_Audit_Properties() + { + var mapper = CreateMapper( + cfg => cfg + .CreateMap() + .IgnoreFullAuditedObjectProperties() + ); + + var obj2 = mapper.Map( + new SimpleClassAudited1 + { + CreationTime = DateTime.Now, + CreatorId = Guid.NewGuid(), + LastModificationTime = DateTime.Now, + LastModifierId = Guid.NewGuid(), + DeleterId = Guid.NewGuid(), + DeletionTime = DateTime.Now, + IsDeleted = true + } + ); + + obj2.CreationTime.ShouldBe(default); + obj2.CreatorId.ShouldBeNull(); + obj2.LastModificationTime.ShouldBe(default); + obj2.LastModifierId.ShouldBeNull(); + obj2.DeleterId.ShouldBeNull(); + obj2.DeletionTime.ShouldBeNull(); + obj2.IsDeleted.ShouldBeFalse(); + } + + [Fact] + public void Should_Ignore_Audit_Properties_With_User() + { + var mapper = CreateMapper( + cfg => cfg + .CreateMap() + .IgnoreFullAuditedObjectProperties() + ); + + var obj2 = mapper.Map( + new SimpleClassAuditedWithUser1 + { + CreationTime = DateTime.Now, + CreatorId = Guid.NewGuid(), + LastModificationTime = DateTime.Now, + LastModifierId = Guid.NewGuid(), + DeleterId = Guid.NewGuid(), + DeletionTime = DateTime.Now, + IsDeleted = true, + Creator = new SimpleUser(), + Deleter = new SimpleUser(), + LastModifier = new SimpleUser() + } + ); + + obj2.CreationTime.ShouldBe(default); + obj2.CreatorId.ShouldBeNull(); + obj2.LastModificationTime.ShouldBe(default); + obj2.LastModifierId.ShouldBeNull(); + obj2.DeleterId.ShouldBeNull(); + obj2.DeletionTime.ShouldBeNull(); + obj2.IsDeleted.ShouldBeFalse(); + obj2.Creator.ShouldBeNull(); + obj2.Deleter.ShouldBeNull(); + obj2.LastModifier.ShouldBeNull(); + } + + private static IMapper CreateMapper(Action configure) + { + var configuration = new MapperConfiguration(configure); + configuration.AssertConfigurationIsValid(); + return configuration.CreateMapper(); + } + + public class SimpleClass1 + { + public string Value1 { get; set; } + public string Value2 { get; set; } + } + + public class SimpleClass2 + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + } + + public class SimpleClassAudited1 : IFullAuditedObject + { + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + } + + public class SimpleClassAudited2 : IFullAuditedObject + { + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + } + + public class SimpleClassAuditedWithUser1 : IFullAuditedObject + { + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + public SimpleUser Creator { get; set; } + public SimpleUser LastModifier { get; set; } + public SimpleUser Deleter { get; set; } + } + + public class SimpleClassAuditedWithUser2 : IFullAuditedObject + { + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + public SimpleUser Creator { get; set; } + public SimpleUser LastModifier { get; set; } + public SimpleUser Deleter { get; set; } + } + + public class SimpleUser + { + + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs b/framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs index 93e2ef5824..9c8926f38a 100644 --- a/framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs @@ -1,5 +1,6 @@ using System.Linq; using Shouldly; +using Volo.Abp; using Xunit; namespace System.Collections.Generic @@ -171,5 +172,36 @@ namespace System.Collections.Generic list[1].ShouldBe(42); list[2].ShouldBe(3); } + + [Fact] + public void SortByDependencies() + { + var dependencies = new Dictionary + { + {'A', new[] {'B', 'G'}}, + {'B', new[] {'C', 'E'}}, + {'C', new[] {'D'}}, + {'D', new char[0]}, + {'E', new[] {'C', 'F'}}, + {'F', new[] {'C'}}, + {'G', new[] {'F'}} + }; + + for (int i = 0; i < 3; i++) + { + var list = RandomHelper + .GenerateRandomizedList(new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G'}); + + list = list.SortByDependencies(c => dependencies[c]); + + foreach (var dependency in dependencies) + { + foreach (var dependedValue in dependency.Value) + { + list.IndexOf(dependency.Key).ShouldBeGreaterThan(list.IndexOf(dependedValue)); + } + } + } + } } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json new file mode 100644 index 0000000000..6c764b21a2 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json @@ -0,0 +1,6 @@ +{ + "culture": "cs", + "texts": { + "hello": "Ahoj" + } +} diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json index 70d0b2b52e..fd029791dc 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json @@ -1,5 +1,5 @@ { - "culture": "de", + "culture": "en", "texts": { "hello": "Hello" } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/cs.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/cs.json index 6f249267c0..db2b0ccc4a 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/cs.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/cs.json index 9fd414c139..f573dae436 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/cs.json +++ b/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ů" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json index 88593c2ba8..433cb0b72e 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/cs.json @@ -8,4 +8,4 @@ "Universe": "Vesmír", "FortyTwo": "Čtyřicet dva" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json index 8054f6de70..a345698004 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/cs.json @@ -3,4 +3,4 @@ "texts": { "SeeYou": "Měj se" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/cs.json b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/cs.json new file mode 100644 index 0000000000..de5a5b79e3 --- /dev/null +++ b/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áš?" + } +} diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json index ac8b58ee1e..120060c4f4 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json +++ b/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." } -} \ No newline at end of file +} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj index a38a51a16c..17a164e612 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj @@ -17,10 +17,8 @@ - - diff --git a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs index 20c42cc4c1..28cb7c7e0a 100644 --- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs +++ b/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>(); - var accountResource = context.ServiceProvider.GetRequiredService>(); + var uiResource = context.GetLocalizer(); + var accountResource = context.GetLocalizer(); 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; } } -} \ No newline at end of file +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Modules/Account/Components/Toolbar/UserLoginLink/Default.cshtml b/modules/account/src/Volo.Abp.Account.Web/Modules/Account/Components/Toolbar/UserLoginLink/Default.cshtml index 451a65b2dc..2331409857 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Modules/Account/Components/Toolbar/UserLoginLink/Default.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Modules/Account/Components/Toolbar/UserLoginLink/Default.cshtml @@ -1,4 +1,4 @@ @using Localization.Resources.AbpUi @using Microsoft.AspNetCore.Mvc.Localization @inject IHtmlLocalizer L -@L["Login"] +@L["Login"] diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs index f5dbba8b2f..41bdd93647 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Account.Localization; @@ -73,7 +74,7 @@ namespace Volo.Abp.Account.Web.Pages.Account protected virtual string GetAppHomeUrl() { - return "/"; //TODO: ??? + return "~/"; //TODO: ??? } } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs index 3b5a5b2cd1..87c7131305 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs @@ -59,7 +59,7 @@ namespace Volo.Abp.Account.Web.Pages.Account await SignInManager.SignInAsync(user, isPersistent: false); - return Redirect(ReturnUrl ?? "/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow! + return Redirect(ReturnUrl ?? "~/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow! } protected virtual async Task CheckSelfRegistrationAsync() diff --git a/modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj b/modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj index 09e4b2cc6f..a77cbad333 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj +++ b/modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj @@ -17,22 +17,18 @@ - - - - - + diff --git a/modules/blob-storing-database/Volo.Abp.BlobStoring.Database.sln b/modules/blob-storing-database/Volo.Abp.BlobStoring.Database.sln index 37fafbe265..e33e90fa86 100644 --- a/modules/blob-storing-database/Volo.Abp.BlobStoring.Database.sln +++ b/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} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.sln b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.sln new file mode 100644 index 0000000000..250233c828 --- /dev/null +++ b/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 diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobService.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobService.cs new file mode 100644 index 0000000000..58924871d1 --- /dev/null +++ b/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 _container; + + public BlobService(IBlobContainer 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"); + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.ConsoleApp.csproj new file mode 100644 index 0000000000..61af5fc4ce --- /dev/null +++ b/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 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppHostedService.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppHostedService.cs new file mode 100644 index 0000000000..06336ad75a --- /dev/null +++ b/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(options => + { + options.UseAutofac(); + options.Services.AddLogging(c => c.AddSerilog()); + })) + { + application.Initialize(); + + var blobService = application.ServiceProvider.GetService(); + + await blobService.SaveFile("Test File 2", "Test Content 2"); + + application.Shutdown(); + } + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppModule.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ConsoleAppConsoleAppModule.cs new file mode 100644 index 0000000000..5a6691c439 --- /dev/null +++ b/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(); + + Configure(options => + { + options.Containers.ConfigureDefault(container => + { + container.ProviderType = typeof(DatabaseBlobProvider); + }); + }); + } + + private void ConfigureEntityFramework(ServiceConfigurationContext context) + { + Configure(options => + { + options.ConnectionStrings.Default = "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True;MultipleActiveResultSets=true"; + }); + + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(true); + }); + + Configure(x => + { + x.UseSqlServer(); + }); + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContext.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContext.cs new file mode 100644 index 0000000000..f7ffc72d43 --- /dev/null +++ b/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 + { + public BlobStoringHostDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureBlobStoring(); + } + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContextFactory.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbContextFactory.cs new file mode 100644 index 0000000000..e5c482f49f --- /dev/null +++ b/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 + { + public BlobStoringHostDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + + var builder = new DbContextOptionsBuilder() + .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(); + } + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbSchemaMigrator.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/BlobStoringHostDbSchemaMigrator.cs new file mode 100644 index 0000000000..6494eb43c7 --- /dev/null +++ b/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() + .Database + .MigrateAsync(); + } + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/IBlobStoringHostDbSchemaMigrator.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/EfCore/IBlobStoringHostDbSchemaMigrator.cs new file mode 100644 index 0000000000..27e14557b6 --- /dev/null +++ b/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(); + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/IBlobService.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/IBlobService.cs new file mode 100644 index 0000000000..32daf0b0fc --- /dev/null +++ b/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"); + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.Designer.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.Designer.cs new file mode 100644 index 0000000000..23fe326a47 --- /dev/null +++ b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.Designer.cs @@ -0,0 +1,97 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasColumnType("varbinary(max)") + .HasMaxLength(2147483647); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531134550_Initial.cs new file mode 100644 index 0000000000..d1ee75ac7f --- /dev/null +++ b/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(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + Name = table.Column(maxLength: 128, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBlobContainers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpBlobs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + ContainerId = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + Name = table.Column(maxLength: 256, nullable: false), + Content = table.Column(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"); + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.Designer.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.Designer.cs new file mode 100644 index 0000000000..1214d7f500 --- /dev/null +++ b/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 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasColumnType("varbinary(max)") + .HasMaxLength(2147483647); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("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 + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200531143839_FK_Added.cs new file mode 100644 index 0000000000..4411063f94 --- /dev/null +++ b/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"); + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs new file mode 100644 index 0000000000..278eb1f72c --- /dev/null +++ b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs @@ -0,0 +1,106 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasColumnType("varbinary(max)") + .HasMaxLength(2147483647); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("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 + } + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ProfilePictureContainer.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/ProfilePictureContainer.cs new file mode 100644 index 0000000000..dd7a683ba5 --- /dev/null +++ b/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 + { + + } +} \ No newline at end of file diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Program.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Program.cs new file mode 100644 index 0000000000..3ae0be0e44 --- /dev/null +++ b/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 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(); + }); + } +} diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json new file mode 100644 index 0000000000..2e1ff4f771 --- /dev/null +++ b/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" + } +} diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/cs.json b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/cs.json index 6a060a54c1..7e0fbb38b3 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/en.json b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/en.json index 171d9a1220..bb66921a1d 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo/Abp/BlobStoring/Database/Localization/en.json +++ b/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" } } \ No newline at end of file diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs index 9514617779..be8625e9e6 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs +++ b/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().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().WithMany().HasForeignKey(p => p.ContainerId); + b.HasIndex(x => new {x.TenantId, x.ContainerId, x.Name}); }); } diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/cs.json b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/cs.json index 9b781b029e..5b11dd808c 100644 --- a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/cs.json b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/cs.json index 5e49b65288..2761ca0278 100644 --- a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/cs.json +++ b/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!" } -} \ No newline at end of file +} diff --git a/modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs b/modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs index cf1f12ed02..15d9e75184 100644 --- a/modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs +++ b/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(); - var l = context.ServiceProvider.GetRequiredService>(); + var l = context.GetLocalizer(); - 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")); } diff --git a/modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj b/modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj index 19d156f10b..3760fa0539 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj +++ b/modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj @@ -23,10 +23,8 @@ - - diff --git a/modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj b/modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj index 57b87b9e72..e8358805b7 100644 --- a/modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj +++ b/modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj @@ -20,11 +20,9 @@ - - diff --git a/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json b/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json index 54e544e43e..3ffad5d85a 100644 --- a/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json +++ b/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!" } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json index 9c44d1d10f..64ecaa2f47 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs index 92b809bf87..744ccac5b6 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs +++ b/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(); 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); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs b/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs index 4097470c60..51ad4e79b9 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs +++ b/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(); - var l = context.ServiceProvider.GetRequiredService>(); + var l = context.GetLocalizer(); 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")); } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj index 4cad3d9e71..14aa5d167d 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj @@ -23,10 +23,8 @@ - - diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json index 743218aeba..d3c4238d6f 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json +++ b/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." } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj index afec611259..013435afda 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj @@ -24,14 +24,12 @@ - - + + - - diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json index 47f49bbc50..466d626391 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json +++ b/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." } -} \ No newline at end of file +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Volo.Abp.FeatureManagement.Web.csproj b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Volo.Abp.FeatureManagement.Web.csproj index b4917d34d6..a60c57040e 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Volo.Abp.FeatureManagement.Web.csproj +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Volo.Abp.FeatureManagement.Web.csproj @@ -12,10 +12,8 @@ - - diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json index 8517adcf12..04c85027a6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json +++ b/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!" } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs index b06f590066..784ea35c18 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs +++ b/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(); - - 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>(); + var l = context.GetLocalizer(); 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 } } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj b/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj index 98cdf702d4..f5c9ffc3d4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj +++ b/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj @@ -16,13 +16,11 @@ - - diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json index 5b30e44dad..bee3e74fd9 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json +++ b/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!" } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json index 4c500d06eb..f7ebdc1386 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Volo.Abp.PermissionManagement.Web.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Volo.Abp.PermissionManagement.Web.csproj index 2c1e0b290d..3209ee2e20 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Volo.Abp.PermissionManagement.Web.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Volo.Abp.PermissionManagement.Web.csproj @@ -13,10 +13,8 @@ - - diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json index 0cdb16d2d4..a0dc156e88 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs index 59c0518d3c..2c9f555f09 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs +++ b/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>(); + var l = context.GetLocalizer(); context.Menu .GetAdministration() diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Volo.Abp.SettingManagement.Web.csproj b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Volo.Abp.SettingManagement.Web.csproj index cbf526e751..b37ef515df 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Volo.Abp.SettingManagement.Web.csproj +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Volo.Abp.SettingManagement.Web.csproj @@ -20,10 +20,8 @@ - - diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json index 16f967139f..86a0461dd5 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs index e021538a5c..fe5b403ed7 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs +++ b/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(); - var l = context.ServiceProvider.GetRequiredService>(); + var l = context.GetLocalizer(); 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")); } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/_ViewImports.cshtml b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/_ViewImports.cshtml index d1ac64721f..c1da1f5f10 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/_ViewImports.cshtml +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/_ViewImports.cshtml @@ -1,2 +1,4 @@ @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap \ No newline at end of file +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Volo.Abp.TenantManagement.Web.csproj b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Volo.Abp.TenantManagement.Web.csproj index 56e6d3cae7..c558ea9637 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Volo.Abp.TenantManagement.Web.csproj +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Volo.Abp.TenantManagement.Web.csproj @@ -13,10 +13,8 @@ - - diff --git a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/cs.json b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/cs.json index 6a060a54c1..44f8d06288 100644 --- a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/cs.json +++ b/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" } -} \ No newline at end of file +} diff --git a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs index 3dc652d1c7..c6f2585037 100644 --- a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs +++ b/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>(); + var l = context.GetLocalizer(); context.Menu.Items.Add(new ApplicationMenuItem(VirtualFileExplorerMenuNames.Index, l["Menu:VirtualFileExplorer"], icon: "fa fa-file", url: "/VirtualFileExplorer")); diff --git a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Pages/VirtualFileExplorer/Index.cshtml.cs b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Pages/VirtualFileExplorer/Index.cshtml.cs index 4c79e27240..b450531cc8 100644 --- a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Pages/VirtualFileExplorer/Index.cshtml.cs +++ b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Pages/VirtualFileExplorer/Index.cshtml.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.FileProviders; using NUglify.Helpers; @@ -42,7 +43,7 @@ namespace Volo.Abp.VirtualFileExplorer.Web.Pages.VirtualFileExplorer .Where(d => VirtualFileExplorerConsts.AllowFileInfoTypes.Contains(d.GetType().Name)) .OrderByDescending(f => f.IsDirectory).ToList(); - PagerModel = new PagerModel(query.Count, PageSize, CurrentPage, PageSize, $"/VirtualFileExplorer?Path={Path}&PageSize={PageSize}"); + PagerModel = new PagerModel(query.Count, PageSize, CurrentPage, PageSize, $"{Url.Content("~/")}VirtualFileExplorer?Path={Path}&PageSize={PageSize}"); SetViewModel(query.Skip((CurrentPage - 1) * PageSize).Take(PageSize)); SetPathNavigation(); @@ -71,7 +72,7 @@ namespace Volo.Abp.VirtualFileExplorer.Web.Pages.VirtualFileExplorer fileInfoViewModel.Icon = "fas fa-folder"; fileInfoViewModel.FileType = "folder"; fileInfoViewModel.Length = "/"; - fileInfoViewModel.FileName =$"{fileInfo.Name}"; + fileInfoViewModel.FileName =$"{fileInfo.Name}"; } else { @@ -86,7 +87,7 @@ namespace Volo.Abp.VirtualFileExplorer.Web.Pages.VirtualFileExplorer { var navigationBuild = new StringBuilder(); var pathArray = Path.Split('/').Where(p => !p.IsNullOrWhiteSpace()); - var href = "/VirtualFileExplorer?path="; + var href = $"{Url.Content("~/")}VirtualFileExplorer?path="; navigationBuild.Append($"