diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 0c33439726..4d81ba9058 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -148,11 +148,12 @@ "EmailSent": "Email Sent", "SuccessfullySent": "Successfully Sent", "SuccessfullyDeleted": "Successfully Deleted", - "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" , - "BusinessType": "Business Type", - "TotalQuestionCount": "Total question count", - "RemainingQuestionCount": "Remaining question count", + "DiscountRequestDeletionWarningMessage": "Discount request will be deleted", + "BusinessType": "Business Type", + "TotalQuestionCount": "Total question count", + "RemainingQuestionCount": "Remaining question count", "TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCount must be greater than RemainingQuestionCount !", - "QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount and RemainingQuestionCount must be zero or greater than zero !" + "QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount and RemainingQuestionCount must be zero or greater than zero !", + "UnlimitedQuestionCount": "Unlimited question count" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index accf9a91b3..6a1d10ee51 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -39,7 +39,7 @@ "Theming": "Theming", "ThemingExplanationShort": "Use and customize the bootstrap-based standard UI theme or create your own one.", "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms", - "BootstrapTagHelpersDynamicFormsExplanation": "Built-in background job system that can be integrated to Hangfire, RabbitMQ or any tool you like.", //TODO explanation doesn't match. + "BootstrapTagHelpersDynamicFormsExplanation": "Instead of manually writing the repeating details of bootstrap components, Use ABP's tag helpers to simplify it and take advantage of intellisense. Dynamic form can create the complete form from a C# class as the model.", "HTTPAPIsDynamicProxies": "HTTP APIs & Dynamic Proxies", "HTTPAPIsDynamicProxiesExplanation": "Automatically expose application services as REST style HTTP APIs and consume with dynamic JavaScript & C# proxies.", "CompleteArchitectureInfo": "Modern architecture to create maintainable software solutions.", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json index c34a08f7ed..34debb8ec8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json @@ -29,17 +29,17 @@ "Authorization": "Autorização", "AuthorizationExplanation": "Autorização avançada com usuário, função e sistema de permissão refinado. Criada na biblioteca Microsoft Identity.", "MultiTenancy": "Múltiplos inquilinos", - "MultiTenancyExplanation": "Aplicativos SaaS facilitados! Multilocação integrada do banco de dados à interface do usuário.", + "MultiTenancyExplanationShort": "Aplicativos SaaS facilitados! Multilocação integrada do banco de dados à interface do usuário.", "CrossCuttingConcerns": "Características transversais", - "CrossCuttingConcernsExplanation": "Infraestrutura completa para autorização, validação, tratamento de exceções, armazenamento em cache, log de auditoria, gerenciamento de transações e assim por diante.", + "CrossCuttingConcernsExplanationShort": "Infraestrutura completa para autorização, validação, tratamento de exceções, armazenamento em cache, log de auditoria, gerenciamento de transações e assim por diante.", "BuiltInBundlingMinification": "Pacote & Minificação Integrados", "BuiltInBundlingMinificationExplanation": "Pare de usar ferramentas externas para empacotamento e minificação. O ABP oferece uma maneira mais simples, dinâmica, poderosa, modular e integrada!", "VirtualFileSystem": "Sistema de arquivos virtual", "VirtualFileSystemExplanation": "Incorpore visualizações, scripts, estilos, imagens ... aos pacotes/bibliotecas e reutilize-os em diferentes aplicativos.", "Theming": "Theming", - "ThemingExplanation": "Use e personalize o tema da interface do usuário padrão baseado em bootstrap-based ou crie o seu próprio.", + "ThemingExplanationShort": "Use e personalize o tema da interface do usuário padrão baseado em bootstrap-based ou crie o seu próprio.", "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms", - "BootstrapTagHelpersDynamicFormsExplanation": "Sistema de tarefas em segundo plano integrado que pode ser integrado ao Hangfire, RabbitMQ ou a qualquer ferramenta que você desejar.", //TODO explanation doesn't match. + "BootstrapTagHelpersDynamicFormsExplanation": "Em vez de escrever manualmente os detalhes repetidos dos componentes de autoinicialização, use os auxiliares de tag da ABP para simplificá-lo e tirar proveito do intellisense. O formulário dinâmico pode criar o formulário completo a partir de uma classe C# como modelo.", "HTTPAPIsDynamicProxies": "APIs HTTP e proxies dinâmicos", "HTTPAPIsDynamicProxiesExplanation": "Exponha automaticamente os serviços de aplicativo como APIs HTTP do estilo REST e consuma com proxies JavaScript & C # dinâmicos.", "CompleteArchitectureInfo": "Arquitetura moderna para criar soluções de software sustentáveis.", @@ -100,7 +100,6 @@ "DistributedEventBus": "Barramento de Eventos Distribuídos", "DistributedEventBusWithRabbitMQIntegration": "Barramento de Eventos Distribuídos com Integração RabbitMQ", "TestInfrastructure": "Infraestrutura de Teste", - "AuditLogging": "Log de auditoria", "AuditLoggingEntityHistories": "Log de auditoria e históricos de entidades", "ObjectToObjectMapping": "Objeto para Mapeamento de Objetos", "EmailSMSAbstractions": "Abstrações de E-mail e SMS", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index b545cd8e16..7bd02b44ac 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -31,7 +31,7 @@ "MultiTenancy": "多租户", "MultiTenancyExplanationShort": "SaaS应用程序变得简单! 从数据库到UI的多租户集成.", "CrossCuttingConcerns": "横切关注点", - "CrossCuttingConcernsExplanationShort": "完整的基础架构,用于授权,验证,异常处理,缓存,审计日志记录,事务管理等.", + "CrossCuttingConcernsExplanationShort": "完整的基础架构,用于授权,验证,异常处理,缓存,审计日志记录,事务管理等.", "BuiltInBundlingMinification": "内置Bundling & Minification", "BuiltInBundlingMinificationExplanation": "无需使用外部工具进行Bundling & Minification. ABP提供了一种更简单,动态,功能强大,模块化和内置的方式!", "VirtualFileSystem": "虚拟文件系统", @@ -39,7 +39,7 @@ "Theming": "主题", "ThemingExplanationShort": "使用和定制基于bootstrap的标准UI主题,或创建自己的主题.", "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers和动态表单", - "BootstrapTagHelpersDynamicFormsExplanation": "内置的后台作业系统可以集成到Hangfire,RabbitMQ或您喜欢的任何工具中.", //TODO explanation doesn't match. + "BootstrapTagHelpersDynamicFormsExplanation": "与其手动重复编写Bootstrap的组件,不如使用ABP的Tag Helpers利用智能感知来简化它. 动态表单可以从C#类创建完整的表单.", "HTTPAPIsDynamicProxies": "HTTP APIs和动态代理", "HTTPAPIsDynamicProxiesExplanation": "自动将应用程序服务公开为REST样式的HTTP API,并与动态JavaScript和C#代理一起使用.", "CompleteArchitectureInfo": "现代架构用来创建可维护的软件解决方案.", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json index 6c74dbcadd..777c9f6bbd 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json @@ -39,7 +39,7 @@ "Theming": "主題", "ThemingExplanationShort": "使用和訂製基於bootstrap的標準UI主題,或建立自己的主題.", "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers和動態表單", - "BootstrapTagHelpersDynamicFormsExplanation": "內建的背景作業系統可以整合到Hangfire,RabbitMQ或您喜歡的任何工具中.", //TODO explanation doesn't match. + "BootstrapTagHelpersDynamicFormsExplanation": "與其手動重複編寫Bootstrap的組件,不如使用ABP的Tag Helpers利用智能感知來簡化它. 動態表單可以從C#類創建完整的表單.", "HTTPAPIsDynamicProxies": "HTTP APIs和動態代理", "HTTPAPIsDynamicProxiesExplanation": "自動將應用程式服務公開為REST樣式的HTTP API,並與動態JavaScript和C#代理一起使用.", "CompleteArchitectureInfo": "現在架構用來建立可維護的軟體解決方案.", diff --git a/common.props b/common.props index cc85429a5b..636d327043 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 2.9.0 + 3.0.0 $(NoWarn);CS1591 https://abp.io/assets/abp_nupkg.png https://abp.io 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/Blob-Storing.md b/docs/en/Blob-Storing.md new file mode 100644 index 0000000000..d46f6e4cd5 --- /dev/null +++ b/docs/en/Blob-Storing.md @@ -0,0 +1,3 @@ +# Blog Storing + +TODO \ No newline at end of file diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/Post.md b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/Post.md new file mode 100644 index 0000000000..b2903e1218 --- /dev/null +++ b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/Post.md @@ -0,0 +1,294 @@ +# ABP Framework v2.9 Has Been Released + +The **ABP Framework** & and the **ABP Commercial** version 2.9 have been released, which are the last versions before v3.0! This post will cover **what's new** with these this release. + +## What's New with the ABP Framework 2.9? + +You can see all the changes on the [GitHub release notes](https://github.com/abpframework/abp/releases/tag/2.9.0). This post will only cover the important features/changes. + +### Pre-Compiling Razor Pages + +Pre-built pages (for [the application modules](https://docs.abp.io/en/abp/latest/Modules/Index)) and view components were compiling on runtime until this version. Now, they are pre-compiled and we've measured that the application startup time (especially for the MVC UI) has been reduced more than 50%. In other words, it is **two-times faster** than the previous version. The speed change also effects when you visit a page for the first time. + +Here, a test result for the startup application template with v2.8 and v.2.9: + +```` +### v2.8 + +2020-06-04 22:59:04.891 +08:00 [INF] Starting web host. +2020-06-04 22:59:07.662 +08:00 [INF] Now listening on: https://localhost:44391 +2020-06-04 22:59:17.315 +08:00 [INF] Request finished in 7756.6218ms 200 text/html; + +Total: 12.42s + +### v2.9 + +2020-06-04 22:59:13.720 +08:00 [INF] Starting web host. +2020-06-04 22:59:16.639 +08:00 [INF] Now listening on: https://localhost:44369 +2020-06-04 22:59:18.957 +08:00 [INF] Request finished in 1780.5461ms 200 text/html; + +Total: 5.24s +```` + +You do nothing to get the benefit of the new approach. [Overriding UI pages/components](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface) are also just working as before. We will be working on more performance improvements in the v3.0. + +### Organization Unit System + +[The Identity Module](https://docs.abp.io/en/abp/latest/Modules/Identity) now has the most requested feature: Organization Units! + +Organization unit system is used to create a hierarchical organization tree in your application. You can then use this organization tree to authorize data and functionality in your application. + +The documentation will come soon... + +### New Blob Storing Package + +We've created a new [Blob Storing package](https://www.nuget.org/packages/Volo.Abp.BlobStoring) to store arbitrary binary objects. It is generally used to store the content of the files in your application. This package provides an abstraction, so any application or [module](https://docs.abp.io/en/abp/latest/Module-Development-Basics) can save and retrieve files independent from the actual storing provider. + +There are two storage provider currently implemented: + +* [Volo.Abp.BlobStoring.FileSystem](https://www.nuget.org/packages/Volo.Abp.BlobStoring.FileSystem) package stores objects/files in the local file system. +* [Volo.Abp.BlobStoring.Database](https://github.com/abpframework/abp/tree/dev/modules/blob-storing-database) module stores objects/files in a database. It currently supports [Entity Framework Core](https://docs.abp.io/en/abp/latest/Entity-Framework-Core) (so, you can use [any relational DBMS](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Other-DBMS)) and [MongoDB](https://docs.abp.io/en/abp/latest/MongoDB). + +[Azure BLOB provider](https://github.com/abpframework/abp/issues/4098) will be available with v3.0. You can request other cloud providers or contribute yourself on the [GitHub repository](https://github.com/abpframework/abp/issues/new). + +One of the benefits of the blob storing system is that it allows you to create multiple containers (each container is a blob storage) and use different storage providers for each container. + +**Example: Use the default container to save and get a byte array** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBlobContainer _container; + + public MyService(IBlobContainer container) + { + _container = container; + } + + public async Task FooAsync() + { + //Save a BLOB + byte[] bytes = GetBytesFromSomeWhere(); + await _container.SaveAsync("my-unique-blob-name", bytes); + + //Retrieve a BLOB + bytes = await _container.GetAllBytesAsync("my-unique-blob-name"); + } +} +```` + +It can work with `byte[]` and `Stream` objects. + +**Example: Use a typed (named) container to save and get a stream** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBlobContainer _container; + + public MyService(IBlobContainer container) + { + _container = container; + } + + public async Task FooAsync() + { + //Save a BLOB + Stream stream = GetStreamFromSomeWhere(); + await _container.SaveAsync("my-unique-blob-name", stream); + + //Retrieve a BLOB + stream = await _container.GetAsync("my-unique-blob-name"); + } +} +```` + +`TestContainer` is an empty class that has no purpose than identifying the container: + +````csharp +[BlobContainerName("test")] //specifies the name of the container +public class TestContainer +{ + +} +```` + +A typed (named) container can be configured to use a different storing provider than the default one. It is a good practice to always use a typed container while developing re-usable modules, so the final application can configure provider for this container without effecting the other containers. + +**Example: Configure the File System provider for the `TestContainer`** + +````csharp +Configure(options => +{ + options.Containers.Configure(configuration => + { + configuration.UseFileSystem(fileSystem => + { + fileSystem.BasePath = "C:\\MyStorageFolder"; + }); + }); +}); +```` + +See the [blob storing documentation](https://docs.abp.io/en/abp/latest/Blob-Storing) for more information. + +### Oracle Integration Package for Entity Framework Core + +We've created an [integration package for Oracle](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart), so you can easily switch to the Oracle for the EF Core. It is tested for the framework and pre-built modules. + +[See the documentation](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Oracle) to start using the Oracle integration package. + +### Automatically Determining the Database Provider + +When you develop a **reusable application module** with EF Core integration, you generally want to develop your module **DBMS independent**. However, there are minor (sometimes major) differences between different DBMSs. If you perform a custom mapping based on the DBMS, you can now use `ModelBuilder.IsUsingXXX()` extension methods: + +````csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(b => + { + //... + if (modelBuilder.IsUsingPostgreSql()) //Check if using PostgreSQL! + { + b.Property(x => x.Number).HasMaxLength(20); + } + else + { + b.Property(x => x.Number).HasMaxLength(32); + } + }); +} +```` + +Beside the stupid example above, you can configure your mapping however you need! + +### ABP CLI: Translate Command + +`abp translate` is a new command that simplifies to translate [localization](https://docs.abp.io/en/abp/latest/Localization) files when you have multiple JSON localization files in a source control repository. + +The main purpose of this command is to **translate the ABP Framework** localization files (since the [abp repository](https://github.com/abpframework/abp) has tens of localization files to be translated in different folders). + +It is appreciated if you use this command to translate the framework resources **for your mother language**. + +See [the documentation](https://docs.abp.io/en/abp/latest/CLI#translate) to learn how to use it. Also see [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index). + +### The New Virtual File System Explorer Module + +Thanks to [@liangshiw](https://github.com/liangshiw) created and contributed a new module to explore files in the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System). It works for MVC UI and shows all the virtual files in the application. Example screenshots: + +![virtual-file-explorer-1](virtual-file-explorer-1.png) + +![virtual-file-explorer-2](virtual-file-explorer-2.png) + +[See the documentation](https://docs.abp.io/en/abp/latest/Modules/Virtual-File-Explorer) to learn how to use it. + +### Sample Application: SignalR with Tiered Architecture + +Implementing SignalR in a distributed/tiered architecture can be challenging. We've created a sample application that demonstrate how to implement it using the [SignalR integration](https://docs.abp.io/en/abp/latest/SignalR-Integration) and the [distributed event bus](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus) system easily. + +See [the source code](https://github.com/abpframework/abp-samples/tree/master/SignalRTieredDemo) of the sample solution. + +**An article is on the road** that will deeply explain the solution. Follow the [@abpframework](https://twitter.com/abpframework) Twitter account. + +![signalr-tiered-demo](signalr-tiered-demo.png) + +*A picture from the article that shows the communication diagram of the solution* + +### About gRPC + +We've created a sample application to show how to create and consume gRPC endpoints in your ABP based applications. + +See [the source code](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) on GitHub. + +We were planning to create gRPC endpoints for all the pre-built application modules, but we see that ASP.NET Core gRPC integration is not mature enough and doesn't support some common deployment scenarios yet. So, deferring this to the next versions ([see this comment](https://github.com/abpframework/abp/issues/2882#issuecomment-633080242) for more). However, it is pretty standard if you want to use gRPC in your applications. ABP Framework has no issue with gRPC. Just check the [sample application](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo). + +### Others + +* [Time zone system](https://github.com/abpframework/abp/pull/3933) to support different time zones for an application. +* Support for [virtual path deployment](https://github.com/abpframework/abp/issues/4089) on IIS. +* RTL support for the Angular UI. + +See the [GitHub release notes](https://github.com/abpframework/abp/releases/tag/2.9.0) for others updates. + +## What's New with the ABP Commercial 2.9 + +In addition to all the features coming with the ABP Framework, the ABP Commercial has additional features with this release, as always. This section covers the [ABP Commercial](https://commercial.abp.io/) highlights in the version 2.9. + +### Organization Unit Management UI + +We've created the UI for manage organization units, their members and roles for the ABP Commercial [Identity Module](https://commercial.abp.io/modules/Volo.Identity.Pro): + +![organization-units](organization-units.png) + +OU management is available for both of the MVC (Razor Pages) and the Angular user interfaces. + +### Chat Module Angular UI + +We had introduced a new [chat module](https://commercial.abp.io/modules/Volo.Chat) in the previous version, which was only supporting the ASP.NET Core MVC / Razor Pages UI. Now, it has also an Angular UI option. + +![abp-chat-module](abp-chat-module.png) + +*A screenshot from the chat module - two users are sending messages to each other* + +### Easy CRM Angular UI + +Easy CRM is a sample application that is built on the ABP Commercial to provide a relatively complex application to the ABP Commercial customers. In the version 2.7, we have lunched it with MVC / Razor Pages UI. With the 2.9 version, we are releasing the Angular UI for the Easy CRM application. + +![easy-crm](easy-crm.png) + +*A screenshot from the "Order Details" page of the Easy CRM application.* + +See the [Easy CRM document](https://docs.abp.io/en/commercial/latest/samples/easy-crm) to learn how to download and run it. + +### Module Code Generation for the ABP Suite + +[ABP Suite](https://commercial.abp.io/tools/suite) is a tool that's main feature is to [generate code](https://docs.abp.io/en/commercial/latest/abp-suite/generating-crud-page) for complete CRUD functionality for an entity, from database to the UI layer. + +![suite](suite.png) + +*A screenshot from the ABP Suite: Define the properties of a new entity and let it to create the application code for you!* + +It was working only for [the application template](https://docs.abp.io/en/commercial/latest/startup-templates/application/index) until this release. Now, it supports to generate code for the [module projects](https://docs.abp.io/en/commercial/latest/startup-templates/module/index) too. That's a great way to create reusable application modules by taking the power of the code generation. + +In addition to this main feature, we added many minor enhancements on the ABP Suite in this release. + +> Notice: Generating code for the module template is currently in beta. Please inform us if you find any bug. + +### Lepton Theme + +[Lepton Theme](https://commercial.abp.io/themes) is the commercial theme we've developed for the ABP Commercial; + +* It is 100% bootstrap compatible - so you don't write theme specific HTML! +* Provides different kind of styles - you see the material style in the picture below. +* Provides different kind of layouts (side/top menu, fluid/boxed layout...). +* It is lightweight, responsive and modern. +* And... it is upgradeable with no cost! You just update a NuGet/NPM package to get the new features. + +We've create its own web site: [http://leptontheme.com/](http://leptontheme.com/) + +You can view all the components together, independent from an application: + +![lepton-theme](lepton-theme.png) + +This web site is currently in a very early stage. We will be documenting and improving this web site to be a reference for your development and explore the features of the theme. + +### Coming Soon: The File management Module + +Based on the new blob storing system (introduced above), we've started to build a file management module that is used to manage (navigate/upload/download) a hierarchical file system on your application and share the files between your users and with your customers. + +We plan to release the initial version with the ABP Commercial v3.0 and continue to improve it with the subsequent releases. + +## About the Next Version: 3.0 + +We have added many new features with the [v2.8](https://blog.abp.io/abp/ABP-v2.8.0-Releases-%26-Road-Map) and v2.9. In the next version, we will completely focus on the **documentation, performance improvements** and and other enhancements as well as bug fixes. + +For a long time, we were releasing a new feature version in every 2 weeks. We will continue to this approach after v3.0. But, as an exception to the v3.0, the development cycle will be ~4 weeks. **The planned release date for the v3.0 is the July 1, 2020**. + +## Bonus: Articles! + +Beside developing our products, our team are constantly writing articles/tutorials on various topics. You may want to check the latest articles: + +* [ASP.NET Core 3.1 WebHook Implementation Using Pub/Sub](https://volosoft.com/blog/ASP.NET-CORE-3.1-Webhook-Implementation-Using-Pub-Sub) +* [Using Azure Key Vault with ASP.NET Core](https://volosoft.com/blog/Using-Azure-Key-Vault-with-ASP.NET-Core) \ No newline at end of file diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png new file mode 100644 index 0000000000..88509b6022 Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png new file mode 100644 index 0000000000..829f7b366f Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png new file mode 100644 index 0000000000..d471078deb Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png new file mode 100644 index 0000000000..57d0399860 Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png new file mode 100644 index 0000000000..bb81ddf37a Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/suite.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/suite.png new file mode 100644 index 0000000000..fb5eac6012 Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/suite.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png new file mode 100644 index 0000000000..99cc1bb49d Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png differ diff --git a/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png new file mode 100644 index 0000000000..cac68ae661 Binary files /dev/null and b/docs/en/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png differ diff --git a/docs/en/Contribution/Index.md b/docs/en/Contribution/Index.md index d753dc6bc2..871ec0b985 100644 --- a/docs/en/Contribution/Index.md +++ b/docs/en/Contribution/Index.md @@ -41,19 +41,22 @@ A new language is published after these minimum translations have been completed ABP framework has a flexible [localization system](../Localization.md). You can create localized user interfaces for your own application. -In addition to that, the framework and pre-build modules have already localized texts. As an example, see [the localization texts for the Volo.Abp.UI package](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). +In addition to that, the framework and the [pre-build modules](https://docs.abp.io/en/abp/latest/Modules/Index) have localized texts. As an example, see [the localization texts for the Volo.Abp.UI package](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). -You can create a new file in the [same folder](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) to translate it. +#### Using the "abp translate" command + +This is the recommended approach, since it automatically finds all missing texts for a specific culture and lets you to translate in one place. * Clone the [ABP repository](https://github.com/abpframework/abp/) from Github. -* Create a new file for the target language for a localization text (json) file (near to the en.json file). -* Copy all texts from the en.json file. -* Translate the texts. -* Send pull request on Github. +* Install the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) if you haven't installed before. +* Run `abp translate -c ` command for your language in the root folder of the abp repository. For example, use `abp translate -c fr` for French. Check [this document](https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/supported-culture-codes) to find the culture code for your language. +* This command creates a file in the same folder, named `abp-translation.json`. Open this file in your favorite editor and fill the missing text values. +* Once you done the translation, use `abp translate -a` command to apply changes to the related files. +* Send a pull request on GitHub. -You can also use the `abp translate` command of [ABP CLI](CLI.md) to translate localized texts. +#### Manual Translation -ABP is a modular framework. So there are many localization text resource, one per module. To find all .json files, you can search for "en.json" after cloning the repository. You can also check [this list](Localization-Text-Files.md) for a list of localization text files. +If you want to make a change on a specific resource file, you can find the file yourself, make the necessary change (or create a new file for your language) and send a pull request on GitHub. ### Blog Posts & Tutorials 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/Entity-Framework-Core-Oracle.md b/docs/en/Entity-Framework-Core-Oracle.md index 3c74cb6d8c..6ac414ebce 100644 --- a/docs/en/Entity-Framework-Core-Oracle.md +++ b/docs/en/Entity-Framework-Core-Oracle.md @@ -22,19 +22,19 @@ Find `UseSqlServer()` calls in your solution, replace with `UseOracle()`. Check In the `CreateDbContext()` method of the *YourProjectName*MigrationsDbContextFactory.cs, replace the following code block -``` +```csharp var builder = new DbContextOptionsBuilder() .UseSqlServer(configuration.GetConnectionString("Default")); ``` with this one -``` +```csharp var builder = (DbContextOptionsBuilder) new DbContextOptionsBuilder().UseOracle ( configuration.GetConnectionString("Default") ); -``` +``` > Depending on your solution structure, you may find more code files need to be changed. @@ -44,11 +44,6 @@ Oracle connection strings are different than SQL Server connection strings. So, You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. -A sample connection string for Oracle: -``` -Data Source=localhost;User Id=myuser;Password=mypassword; -``` - ## Re-Generate the Migrations The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) by default. 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-Extensions.md b/docs/en/Object-Extensions.md index 8c7cca4037..308be4bfa7 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -2,7 +2,7 @@ ABP Framework provides an **object extension system** to allow you to **add extra properties** to an existing object **without modifying** the related class. This allows to extend functionalities implemented by a depended [application module](Modules/Index.md), especially when you want to [extend entities](Customizing-Application-Modules-Extending-Entities.md) and [DTOs](Customizing-Application-Modules-Overriding-Services.md) defined by the module. -> Object extension system is not normally not needed for your own objects since you can easily add regular properties to your own classes. +> Object extension system normally is not needed for your own objects since you can easily add regular properties to your own classes. ## IHasExtraProperties Interface @@ -409,4 +409,4 @@ ObjectExtensionManager.Instance ); ```` -See the [Entity Framework Core Integration document](Entity-Framework-Core.md) for more. \ No newline at end of file +See the [Entity Framework Core Integration document](Entity-Framework-Core.md) for more. 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/en/Road-Map.md b/docs/en/Road-Map.md index 4ef8500e83..a3af5a21f6 100644 --- a/docs/en/Road-Map.md +++ b/docs/en/Road-Map.md @@ -4,8 +4,27 @@ You can always check the milestone planning and the prioritized backlog issues o While we will **continue to add other exciting features**, we will work on the following major items in the **middle term**: -* **gRPC integration** and implementation for all the pre-built modules. * **Blazor UI** for the framework and all the pre-built modules. * **.NET 5.0**! As Microsoft has announced that the .NET 5.0 will be released in November 2020, we will prepare for this change before and move to the .NET 5.0 just after Microsoft releases it. We hope a smooth transition. -Please create an issue on [the GitHub repository](https://github.com/abpframework/abp) for your feature requests, but first search in in the existing issues. \ No newline at end of file +Beside this middle term goals, there are many features in the [backlog](https://github.com/abpframework/abp/milestone/2). Here, a list of some major items in the backlog; + +* [#4098](https://github.com/abpframework/abp/issues/4098) / Blob Storing Azure provider. +* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a **gRPC integration** infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index)) +* [#236](https://github.com/abpframework/abp/issues/236) Resource based authorization system +* [#1754](https://github.com/abpframework/abp/issues/1754) / Multi-lingual entities +* [#347](https://github.com/abpframework/abp/issues/347) / Support MongoDB ACID transactions +* [#633](https://github.com/abpframework/abp/issues/633) / Realtime notification system +* [#57](https://github.com/abpframework/abp/issues/57) / Built-in CQRS infrastructure +* [#4222](https://github.com/abpframework/abp/issues/4222) / Kafka integration for the Distributed Event Bus +* [#336](https://github.com/abpframework/abp/issues/336) / Health Check abstraction +* [#2532](https://github.com/abpframework/abp/issues/2532), [#2564](https://github.com/abpframework/abp/issues/2465) / CosmosDB integration with EF Core and MongoDB API +* [#1168](https://github.com/abpframework/abp/issues/1168) / Official Vue UI startup template +* [#1638](https://github.com/abpframework/abp/issues/1638) Official React startup template +* [#4223](https://github.com/abpframework/abp/issues/4223) / WebHook system +* [#162](https://github.com/abpframework/abp/issues/162) / Azure ElasticDB Integration for multitenancy +* [#2296](https://github.com/abpframework/abp/issues/2296) / Feature toggling infrastructure + +The backlog items are subject to change. We are adding new items and changing priorities based on the community feedbacks and goals of the project. + +Vote for your favorite feature on the related GitHub issues (and write your thoughts). You can create an issue on [the GitHub repository](https://github.com/abpframework/abp) for your feature requests, but first search in in the existing issues. \ No newline at end of file diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index be812cc162..bd08cbdcd5 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -607,7 +607,7 @@ namespace Acme.BookStore.Web.Menus { //<-- added the below code context.Menu.AddItem( - new ApplicationMenuItem("BooksStore", l["Menu:BookStore"]) + new ApplicationMenuItem("BooksStore", l["Menu:BookStore"], icon: "fa fa-book") .AddItem( new ApplicationMenuItem("BooksStore.Books", l["Menu:Books"], url: "/Books") ) @@ -646,7 +646,16 @@ Open the `en.json` (*English translations*) file and add the below localization "Type": "Type", "Price": "Price", "CreationTime": "Creation time", - "AreYouSureToDelete": "Are you sure you want to delete this item?" + "AreYouSureToDelete": "Are you sure you want to delete this item?", + "Enum:BookType:0": "Undefined", + "Enum:BookType:1": "Adventure", + "Enum:BookType:2": "Biography", + "Enum:BookType:3": "Dystopia", + "Enum:BookType:4": "Fantastic", + "Enum:BookType:5": "Horror", + "Enum:BookType:6": "Science", + "Enum:BookType:7": "ScienceFiction", + "Enum:BookType:8": "Poetry" } } ```` @@ -716,7 +725,11 @@ $(function () { ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList), columnDefs: [ { data: "name" }, - { data: "type" }, + { data: "type", + render: function(data){ + return l('Enum:BookType:' + data); + } + }, { data: "publishDate" }, { data: "price" }, { data: "creationTime" } diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/Post.md b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/Post.md new file mode 100644 index 0000000000..da13682869 --- /dev/null +++ b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/Post.md @@ -0,0 +1,294 @@ +# ABP框架v2.9已经发布 + +**ABP框架**和**ABP商业版**2.9已经发布,这是3.0之前的最后一个版本!这篇文章将涵盖本次发布中的**新增内容**. + +## ABP框架2.9有哪些新增内容? + +你可以中[GitHub的发行说明](https://github.com/abpframework/abp/releases/tag/2.9.0)中看到所有的变更.这篇文章将只包括重要特征/变更. + +### 预编译Razor Pages + +在之前的版本, 预构建的页面(为[应用模块](https://docs.abp.io/en/abp/latest/Modules/Index))和视图组件是在运行时编译. 现在,它们使用了预编译. 我们测量的应用程序启动时间(尤其是MVC UI)已经减少了50%以上.换句话说,它比之前的版本快**两倍**.速度变化也影响你第一次访问某一个页面时. + +这是一个v2.8和v2.9启动应用程序模板的对比结果: + +```` +### v2.8 + +2020-06-04 22:59:04.891 +08:00 [INF] Starting web host. +2020-06-04 22:59:07.662 +08:00 [INF] Now listening on: https://localhost:44391 +2020-06-04 22:59:17.315 +08:00 [INF] Request finished in 7756.6218ms 200 text/html; + +Total: 12.42s + +### v2.9 + +2020-06-04 22:59:13.720 +08:00 [INF] Starting web host. +2020-06-04 22:59:16.639 +08:00 [INF] Now listening on: https://localhost:44369 +2020-06-04 22:59:18.957 +08:00 [INF] Request finished in 1780.5461ms 200 text/html; + +Total: 5.24s +```` + +你不用做任何改动就能获得新方法带来的益处.[重写UI页/组件](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface)和之前一样也能正常工作.我们将在v3.0中继续致力于性能上的提升. + +### 组织单元系统 + +[Identity模块](https://docs.abp.io/en/abp/latest/Modules/Identity)现在有了呼声最高的功能: 组织单元! + +组织单元系统用来在应用程序中创建分层组织树.这样你可以使用该组织树来授权应用程序中的数据和功能. + +文档将很快到来...... + +### 新的Blob存储包 + +我们创建了一个新的[Blob存储包](https://www.nuget.org/packages/Volo.Abp.BlobStoring)用来存储任意二进制对象.它一般用于在应用程序中存储文件.这个包提供了一个抽象,因此任何应用程序或[模块](https://docs.abp.io/en/abp/latest/Module-Development-Basics)都能以存储提供器无关的方式来保存和获取文件. + +目前实现了两个存储提供器: + +* [Volo.Abp.BlobStoring.FileSystem](https://www.nuget.org/packages/Volo.Abp.BlobStoring.FileSystem)包, 在本地文件系统中存储对象/文件. +* [Volo.Abp.BlobStoring.Database](https://github.com/abpframework/abp/tree/dev/modules/blob-storing-database)模块, 在数据库中存储对象/文件.目前支持[Entity Framework Core](https://docs.abp.io/en/abp/latest/Entity-Framework-Core)(因此,你可以使用[任何关系数据库](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Other-DBMS)和[MongoDB](https://docs.abp.io/en/abp/latest/MongoDB)). + +[Azure BLOB提供器](https://github.com/abpframework/abp/issues/4098)将会在3.0中可用. 你可请求其他的云提供器或在[GitHub库](https://github.com/abpframework/abp/issues/new)上提交你自己的贡献. + +Blob存储系统的一个好处是,它允许你创建多个容器(每个容器是一个Blob存储),并为每个容器使用不同的存储提供器. + +**示例:使用默认的容器保存和取得一个字节数组** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBlobContainer _container; + + public MyService(IBlobContainer container) + { + _container = container; + } + + public async Task FooAsync() + { + //保存一个BLOB + byte[] bytes = GetBytesFromSomeWhere(); + await _container.SaveAsync("my-unique-blob-name", bytes); + + //获取一个BLOB + bytes = await _container.GetAllBytesAsync("my-unique-blob-name"); + } +} +```` + +它可以使用`byte[]`和`Stream`对象. + +**示例:使用类型化(命名)容器来保存和获取stream** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBlobContainer _container; + + public MyService(IBlobContainer container) + { + _container = container; + } + + public async Task FooAsync() + { + //保存一个BLOB + Stream stream = GetStreamFromSomeWhere(); + await _container.SaveAsync("my-unique-blob-name", stream); + + //获取一个BLOB + stream = await _container.GetAsync("my-unique-blob-name"); + } +} +```` + +`TestContainer`只是一个用来标识容器的空类: + +````csharp +[BlobContainerName("test")] //指定容器的名字 +public class TestContainer +{ + +} +```` + +类型化(命名)容器可被配置为使用不同的存储提供器而不是默认的.在开发可复用的模块时, 始终使用类型化的容器是一个很好的做法,这样最终应用程序可以为这个容器配置提供器,而不影响其他容器. + +**示例:为`TestContainer`配置文件系统提供器** + +````csharp +Configure(options => +{ + options.Containers.Configure(configuration => + { + configuration.UseFileSystem(fileSystem => + { + fileSystem.BasePath = "C:\\MyStorageFolder"; + }); + }); +}); +```` + +查看[blob存储文档](https://docs.abp.io/en/abp/latest/Blob-Storing)以获取更多的信息. + +### Entity Framework Core的Oracle集成包 + +我们创建了一个[Oralce集成包](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Oracle.Devart),这样你就可以为EF Core轻松地切换到Oracle.它已经为框架和预构建的模块进行了测试. + +[查看文档](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Oracle)开始使用Oracle集成包. + +### 自动判断数据库提供器 + +当你用EF Core开发一个**可复用的应用程序模块**时,你通常要将你的模块开发为**DBMS无关**的.但是,不同的DBMS有一些微小的(有时是很大的)区别.现在如何你执行基于DBMS的自定义映射,可以使用`ModelBuilder.IsUsingXXX()`扩展方法: + +````csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(b => + { + //... + if (modelBuilder.IsUsingPostgreSql()) //检查是否在使用PostgreSQL! + { + b.Property(x => x.Number).HasMaxLength(20); + } + else + { + b.Property(x => x.Number).HasMaxLength(32); + } + }); +} +```` + +除了上面这种的傻傻的例子,你可以任意配置你的映射! + +### ABP CLI:翻译命令 + +`abp translate`是一个新的命令,当你的源代码库中包含多个JSON本地化文件时, 它可用来简化翻译[本地化](https://docs.abp.io/en/abp/latest/Localization)文件, + +该命令的主要目的是**翻译ABP框架**的本地化文件(因为[abp库](https://github.com/abpframework/abp)在不同的文件中含有成千上万个本地化文件需要翻译). + +非常感谢如果你使用这个命令将框架资源翻译**为你的母语**. + +查看[文档](https://docs.abp.io/en/abp/latest/CLI#translate)来学习如何使用它.也可查看[贡献指南](https://docs.abp.io/en/abp/latest/Contribution/Index). + +### 新的虚拟文件系统浏览器模块 + +感谢[@liangshiw](https://github.com/liangshiw)创建并贡献了一个新的模块用来浏览[虚拟文件系统](https://docs.abp.io/en/abp/latest/Virtual-File-System)中的文件.它适用于MVC UI并显示所有应用程序中的虚拟文件.示例截图: + +![virtual-file-explorer-1](virtual-file-explorer-1.png) + +![virtual-file-explorer-2](virtual-file-explorer-2.png) + +[查看文档](https://docs.abp.io/en/abp/latest/Modules/Virtual-File-Explorer)学习如何使用它. + +### 示例应用程序:SignalR与分层架构 + +在分布式/分层架构中实施SignalR是具有挑战性的.我们创建了一个示例应用程序演示如何轻松地使用[SignalR集成](https://docs.abp.io/en/abp/latest/SignalR-Integration)和[分布式事件总线](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus)系统 + +查看示例解决方案的[源代码](https://github.com/abpframework/abp-samples/tree/master/SignalRTieredDemo). + +**一篇正在路上的文章**将深入地解释该解决方案.关注[@abpframework](https://twitter.com/abpframework)的Twitter帐号. + +![signalr-tiered-demo](signalr-tiered-demo.png) + +*一张文章中的图片,显示了该解决方案的通信图* + +### 关于gRPC + +我们创建了一个示例应用程序来说明如何在基于ABP的应用程序中创建和使用gRPC端点. + +查看GitHub上的[源码](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo). + +我们本来计划为所有预构建的应用程序模块创建gRPC端点,但我们发现ASP.NET Core gRPC集成还不够成熟,不支持一些常见的部署场景.所以推迟到了下一个版本(更多内容[查看此评论](https://github.com/abpframework/abp/issues/2882#issuecomment-633080242)).但是,在你的应用程序中使用gRPC是非常标准的. ABP框架与gRPC没有问题.看一下[示例应用程序](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo). + +### 其它 + +* [时区系统](https://github.com/abpframework/abp/pull/3933)为应用程序支持不同的时区. +* 在IIS上支持[虚拟路径部署](https://github.com/abpframework/abp/issues/4089). +* 为Angular UI支持RTL. + +其它更新请查看[GitHub发行说明](https://github.com/abpframework/abp/releases/tag/2.9.0). + +## ABP商业版2.9有哪些新增内容 + +与往常一样, 除了ABP框架所有这些功能以外,ABP商业版在本次发布还有一些额外的功能.本节介绍[ABP商业版](https://commercial.abp.io/)在2.9版本中的亮点. + +### 组织单元管理UI + +我们为组织单元创建了UI,管理ABP商业版[Identity模块](https://commercial.abp.io/modules/Volo.Identity.Pro)的成员和角色: + +![organization-units](organization-units.png) + +OU管理适用于MVC(Razor Pages)和Angular用户界面. + +### 聊天模块Angular UI + +我们在前一个版本介绍了新的[聊天模块](https://commercial.abp.io/modules/Volo.Chat), 当时它只有ASP.NET Core MVC / Razor Pages UI. 现在它也包含了一个Angular UI选项. + +![abp-chat-module](abp-chat-module.png) + +*聊天模块的截图 - 两个用户互相发消息* + +### Easy CRM Angular UI + +Easy CRM是建立在ABP商业版上的一个示例应用程序, 用来为ABP商业版客户提供一个相对复杂的应用程序.在2.7版本中,我们已经发布了MVC / Razor Pages UI. 这次2.9版中, 我们为Easy CRM应用程序发布了Angular UI. + +![easy-crm](easy-crm.png) + +*Easy CRM应用程序中"订单详细"的截图.* + +查看[Easy CRM文档](https://docs.abp.io/en/commercial/latest/samples/easy-crm)学习如何下载并运行它. + +### ABP Suite模块代码生成 + +[ABP Suite](https://commercial.abp.io/tools/suite)是一个工具,主要功能是用来为一个实体[生成代码](https://docs.abp.io/en/commercial/latest/abp-suite/generating-crud-page), 从数据库到UI层具有完整的CRUD功能. + +![suite](suite.png) + +*ABP Suite的截图: 定义新实体的属性并且为你生成应用程序代码!* + +在本次发布之前它只工作于[应用程序模板](https://docs.abp.io/en/commercial/latest/startup-templates/application/index).现在,它支持为[模块项目](https://docs.abp.io/en/commercial/latest/startup-templates/module/index)生成代码.利用代码生成的威力来创建可复用应用程序模块是很棒的一个做法. + +除了这个主要功能,我们在这个版本中向ABP Suite添加了许多细微的改进. + +>注意:模块模板代码生成目前处于测试阶段.如果你发现任何bug,请告知我们. + +### Lepton主题 + +[Lepton主题](https://commercial.abp.io/themes)是我们为ABP商业版开发的一个商业主题. + +* 与Bootstrap 100%兼容 - 让你不写主题特定的HTML! +* 提供不同类型的风格 - 看一下下图中的Material风格. +* 提供不同类型的布局(侧/顶部菜单,流式/盒式布局...). +* 轻量化,响应式和现代化. +* 还有...它是可升级的,没有成本!你只需更新NuGet / NPM包来获得新的功能. + +我们创建了它的专属网站:[http://leptontheme.com/](http://leptontheme.com/) + +在这里你可以查看所有的组件, 无需单独的应用程序. + +![lepton-theme](lepton-theme.png) + +这个网站目前正处于一个非常早期的阶段.我们将创建文档和和改进网站, 来为你的开发提供参考和探索主题的功能. + +### 即将推出:文件管理模块 + +基于新的blob存储系统(上面介绍的),我们已经开始构建一个文件管理模块用来管理(浏览/上传/下载)你应用程序中分层文件系统并在用户与客户之间分享文件. + +我们计划在ABP商业版v3.0中发行最初版本,并继续进行后续版本的改进. + +## 关于下一个版本:3.0 + +我们在[v2.8](https://blog.abp.io/abp/ABP-v2.8.0-Releases-%26-Road-Map)和v2.9中增加了许多新的功能.在下一个版本中,我们将完全专注于**文档,性能优化**和其它改进,如bug修复. + +长期以来,我们每2周发布一个新功能版本.我们在v3.0以后继续这种方式.但是,v3.0是一个例外,开发周期大概为4周.**v3.0的计划发布日期是2020年7月1日**. + +## 彩蛋:文章! + +除了开发我们的产品,我们的团队都在不断地撰写各种主题的文章/教程.你可以看一下最新的文章: + +* [ASP.NET Core 3.1使用Pub/Sub实现WebHook](https://volosoft.com/blog/ASP.NET-CORE-3.1-Webhook-Implementation-Using-Pub-Sub) +* [ASP.NET Core使用Azure Key Vault](https://volosoft.com/blog/Using-Azure-Key-Vault-with-ASP.NET-Core) \ No newline at end of file diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png new file mode 100644 index 0000000000..88509b6022 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/abp-chat-module.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png new file mode 100644 index 0000000000..829f7b366f Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/easy-crm.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png new file mode 100644 index 0000000000..d471078deb Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/lepton-theme.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png new file mode 100644 index 0000000000..57d0399860 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/organization-units.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png new file mode 100644 index 0000000000..bb81ddf37a Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/signalr-tiered-demo.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/suite.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/suite.png new file mode 100644 index 0000000000..fb5eac6012 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/suite.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png new file mode 100644 index 0000000000..99cc1bb49d Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-1.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png new file mode 100644 index 0000000000..cac68ae661 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-06-05 v2_9_Release/virtual-file-explorer-2.png differ 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/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/Themes/Basic/Layouts/Account.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index 1f166121be..2c8401aacd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -24,11 +24,12 @@ Layout = null; AbpAntiForgeryManager.SetCookie(); var containerClass = ViewBag.FluidLayout == true ? "container-fluid" : "container"; //TODO: Better and type-safe options + var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty; } - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Account) @@ -48,7 +49,7 @@ @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account) - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Account) @(await Component.InvokeAsync()) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 2f3b2869f3..5e271eabab 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -28,11 +28,13 @@ pageTitle = PageLayout.Content.Title + pageTitle; } + + var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty; } - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Application) @@ -50,7 +52,7 @@ @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Application) - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Application) @(await Component.InvokeAsync()) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 6e47a10c33..8d4eab5167 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -27,11 +27,13 @@ pageTitle = PageLayout.Content.Title + pageTitle; } + + var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty; } - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Empty) @@ -52,7 +54,7 @@ @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Empty) - + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Empty)
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/Pages/Shared/Components/AbpPageSearchBox/AbpPageSearchBoxViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageSearchBox/AbpPageSearchBoxViewComponent.cs new file mode 100644 index 0000000000..d14c92c62e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageSearchBox/AbpPageSearchBoxViewComponent.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox +{ + public class AbpPageSearchBoxViewComponent : AbpViewComponent + { + public IViewComponentResult Invoke() + { + return View("~/Pages/Shared/Components/AbpPageSearchBox/Default.cshtml"); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageSearchBox/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageSearchBox/Default.cshtml new file mode 100644 index 0000000000..a45223e825 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageSearchBox/Default.cshtml @@ -0,0 +1,13 @@ +@using Localization.Resources.AbpUi +@using Microsoft.Extensions.Localization +@inject IStringLocalizer L +
+
+ +
+ + + +
+
+
\ No newline at end of file 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/Commands/GetSourceCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs index c57833c1f7..0a6155fa67 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs @@ -48,16 +48,22 @@ namespace Volo.Abp.Cli.Commands var outputFolder = GetOutPutFolder(commandLineArgs); Logger.LogInformation("Output folder: " + outputFolder); - var gitHubLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubLocalRepositoryPath.Long); - if (gitHubLocalRepositoryPath != null) + var gitHubAbpLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubAbpLocalRepositoryPath.Long); + if (gitHubAbpLocalRepositoryPath != null) { - Logger.LogInformation("GitHub Local Repository Path: " + gitHubLocalRepositoryPath); + Logger.LogInformation("GitHub Abp Local Repository Path: " + gitHubAbpLocalRepositoryPath); + } + + var gitHubVoloLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubVoloLocalRepositoryPath.Long); + if (gitHubVoloLocalRepositoryPath != null) + { + Logger.LogInformation("GitHub Volo Local Repository Path: " + gitHubVoloLocalRepositoryPath); } commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command); await _sourceCodeDownloadService.DownloadAsync( - commandLineArgs.Target, outputFolder, version, gitHubLocalRepositoryPath, commandLineArgs.Options); + commandLineArgs.Target, outputFolder, version, gitHubAbpLocalRepositoryPath, gitHubVoloLocalRepositoryPath, commandLineArgs.Options); } private static string GetOutPutFolder(CommandLineArgs commandLineArgs) @@ -117,11 +123,16 @@ namespace Volo.Abp.Cli.Commands public const string Long = "output-folder"; } - public static class GitHubLocalRepositoryPath + public static class GitHubAbpLocalRepositoryPath { public const string Long = "abp-path"; } + public static class GitHubVoloLocalRepositoryPath + { + public const string Long = "volo-path"; + } + public static class Version { public const string Short = "v"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 5605f357bf..c55e68916c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -86,10 +86,16 @@ namespace Volo.Abp.Cli.Commands Logger.LogInformation("Mobile App: " + mobileApp); } - var gitHubLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubLocalRepositoryPath.Long); - if (gitHubLocalRepositoryPath != null) + var gitHubAbpLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubAbpLocalRepositoryPath.Long); + if (gitHubAbpLocalRepositoryPath != null) { - Logger.LogInformation("GitHub Local Repository Path: " + gitHubLocalRepositoryPath); + Logger.LogInformation("GitHub Abp Local Repository Path: " + gitHubAbpLocalRepositoryPath); + } + + var gitHubVoloLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubVoloLocalRepositoryPath.Long); + if (gitHubVoloLocalRepositoryPath != null) + { + Logger.LogInformation("GitHub Volo Local Repository Path: " + gitHubVoloLocalRepositoryPath); } var templateSource = commandLineArgs.Options.GetOrNull(Options.TemplateSource.Short, Options.TemplateSource.Long); @@ -127,7 +133,8 @@ namespace Volo.Abp.Cli.Commands databaseProvider, uiFramework, mobileApp, - gitHubLocalRepositoryPath, + gitHubAbpLocalRepositoryPath, + gitHubVoloLocalRepositoryPath, templateSource, commandLineArgs.Options, connectionString @@ -299,11 +306,16 @@ namespace Volo.Abp.Cli.Commands public const string Long = "output-folder"; } - public static class GitHubLocalRepositoryPath + public static class GitHubAbpLocalRepositoryPath { public const string Long = "abp-path"; } + public static class GitHubVoloLocalRepositoryPath + { + public const string Long = "volo-path"; + } + public static class Version { public const string Short = "v"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs index 7c8d068e1e..ca01314758 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Cli.Commands.Services Logger = NullLogger.Instance; } - public async Task DownloadAsync(string moduleName, string outputFolder, string version, string gitHubLocalRepositoryPath, AbpCommandLineOptions options) + public async Task DownloadAsync(string moduleName, string outputFolder, string version, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath, AbpCommandLineOptions options) { Logger.LogInformation("Downloading source code of " + moduleName); Logger.LogInformation("Version: " + version); @@ -39,7 +39,8 @@ namespace Volo.Abp.Cli.Commands.Services DatabaseProvider.NotSpecified, UiFramework.NotSpecified, null, - gitHubLocalRepositoryPath, + gitHubAbpLocalRepositoryPath, + gitHubVoloLocalRepositoryPath, null, options ) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs index c7a6cc90f0..698c7f1d8d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs @@ -22,10 +22,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps return; } + var localVoloRepoPath = context.BuildArgs.VoloGitHubLocalRepositoryPath; + new ProjectReferenceReplacer.LocalProjectPathReferenceReplacer( context.Files, context.Module?.Namespace ?? "MyCompanyName.MyProjectName", - localAbpRepoPath + localAbpRepoPath, + localVoloRepoPath ).Run(); } else @@ -177,12 +180,14 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps public class LocalProjectPathReferenceReplacer : ProjectReferenceReplacer { - private readonly string _gitHubLocalRepositoryPath; + private readonly string _gitHubAbpLocalRepositoryPath; + private readonly string _gitHubVoloLocalRepositoryPath; - public LocalProjectPathReferenceReplacer(List entries, string projectName, string gitHubLocalRepositoryPath) + public LocalProjectPathReferenceReplacer(List entries, string projectName, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath) : base(entries, projectName) { - _gitHubLocalRepositoryPath = gitHubLocalRepositoryPath; + _gitHubAbpLocalRepositoryPath = gitHubAbpLocalRepositoryPath; + _gitHubVoloLocalRepositoryPath = gitHubVoloLocalRepositoryPath; } protected override XmlElement GetNewReferenceNode(XmlDocument doc, string oldNodeIncludeValue) @@ -204,9 +209,17 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps includeValue = includeValue.TrimStart('\\'); } - includeValue = _gitHubLocalRepositoryPath.EnsureEndsWith('\\') + includeValue; + if (!string.IsNullOrWhiteSpace(_gitHubVoloLocalRepositoryPath)) + { + if (includeValue.StartsWith("abp\\", StringComparison.InvariantCultureIgnoreCase)) + { + return _gitHubAbpLocalRepositoryPath.EnsureEndsWith('\\') + includeValue.Substring("abp\\".Length); + } + + return _gitHubVoloLocalRepositoryPath.EnsureEndsWith('\\') + "abp\\" + includeValue; + } - return includeValue; + return _gitHubAbpLocalRepositoryPath.EnsureEndsWith('\\') + includeValue; } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs index 70cb98dff0..52fa76e551 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs @@ -24,6 +24,9 @@ namespace Volo.Abp.Cli.ProjectBuilding [CanBeNull] public string AbpGitHubLocalRepositoryPath { get; set; } + [CanBeNull] + public string VoloGitHubLocalRepositoryPath { get; set; } + [CanBeNull] public string TemplateSource { get; set; } @@ -41,6 +44,7 @@ namespace Volo.Abp.Cli.ProjectBuilding UiFramework uiFramework = UiFramework.NotSpecified, MobileApp? mobileApp = null, [CanBeNull] string abpGitHubLocalRepositoryPath = null, + [CanBeNull] string voloGitHubLocalRepositoryPath = null, [CanBeNull] string templateSource = null, Dictionary extraProperties = null, [CanBeNull] string connectionString = null) @@ -52,6 +56,7 @@ namespace Volo.Abp.Cli.ProjectBuilding UiFramework = uiFramework; MobileApp = mobileApp; AbpGitHubLocalRepositoryPath = abpGitHubLocalRepositoryPath; + VoloGitHubLocalRepositoryPath = voloGitHubLocalRepositoryPath; TemplateSource = templateSource; ExtraProperties = extraProperties ?? new Dictionary(); ConnectionString = connectionString; 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.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs index 9af114dfff..890053049f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs @@ -11,6 +11,7 @@ HttpApiClient = 6, Web = 7, EntityFrameworkCore = 8, - MongoDB = 9 + MongoDB = 9, + SignalR = 10 } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs index b2f5421e6e..d4b3a62b94 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs @@ -41,6 +41,10 @@ namespace Volo.Abp.Cli.ProjectModification return FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi"); case NuGetPackageTarget.HttpApiClient: return FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi.Client"); + case NuGetPackageTarget.SignalR: + return FindProjectEndsWith(projectFiles, assemblyNames, ".SignalR") ?? + FindProjectEndsWith(projectFiles, assemblyNames, ".Web") ?? + FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi.Host"); default: return null; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 51a8ee40df..a6ed12730a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -129,6 +129,7 @@ namespace Volo.Abp.Cli.ProjectModification targetModuleFolder, version, null, + null, null ); 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.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs index c9a10c5432..7f9672ce69 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs @@ -32,6 +32,8 @@ namespace Volo.Abp.Http.ProxyScripting.Generators.JQuery AddModuleScript(script, module); } + AddInitializedEventTrigger(script); + return script.ToString(); } @@ -189,6 +191,12 @@ namespace Volo.Abp.Http.ProxyScripting.Generators.JQuery return result; } + + private static void AddInitializedEventTrigger(StringBuilder script) + { + script.AppendLine(); + script.AppendLine("abp.event.trigger('abp.serviceProxyScriptInitialized');"); + } private static string GetNormalizedTypeName(string typeWithAssemblyName) { diff --git a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj index ce26fe7bea..6c19f18397 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj +++ b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj @@ -17,6 +17,7 @@ + diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs index d0a08707b5..7ab97c49fe 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs @@ -1,11 +1,13 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; namespace Volo.Abp.IdentityModel { [DependsOn( - typeof(AbpThreadingModule) + typeof(AbpThreadingModule), + typeof(AbpMultiTenancyModule) )] public class AbpIdentityModelModule : AbpModule { @@ -13,7 +15,7 @@ namespace Volo.Abp.IdentityModel { var configuration = context.Services.GetConfiguration(); - context.Services.AddHttpClient(); + context.Services.AddHttpClient(IdentityModelAuthenticationService.HttpClientName); Configure(configuration); } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs index b78a05c684..c192fc8feb 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs @@ -11,6 +11,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; namespace Volo.Abp.IdentityModel @@ -18,19 +19,23 @@ namespace Volo.Abp.IdentityModel [Dependency(ReplaceServices = true)] public class IdentityModelAuthenticationService : IIdentityModelAuthenticationService, ITransientDependency { + public const string HttpClientName = "IdentityModelAuthenticationServiceHttpClientName"; public ILogger Logger { get; set; } protected AbpIdentityClientOptions ClientOptions { get; } protected ICancellationTokenProvider CancellationTokenProvider { get; } protected IHttpClientFactory HttpClientFactory { get; } + protected ICurrentTenant CurrentTenant { get; } public IdentityModelAuthenticationService( IOptions options, ICancellationTokenProvider cancellationTokenProvider, - IHttpClientFactory httpClientFactory) + IHttpClientFactory httpClientFactory, + ICurrentTenant currentTenant) { ClientOptions = options.Value; CancellationTokenProvider = cancellationTokenProvider; HttpClientFactory = httpClientFactory; + CurrentTenant = currentTenant; Logger = NullLogger.Instance; } @@ -46,7 +51,6 @@ namespace Volo.Abp.IdentityModel SetAccessToken(client, accessToken); return true; - } protected virtual async Task GetAccessTokenOrNullAsync(string identityClientName) @@ -106,7 +110,7 @@ namespace Volo.Abp.IdentityModel protected virtual async Task GetDiscoveryResponse( IdentityClientConfiguration configuration) { - using (var httpClient = HttpClientFactory.CreateClient()) + using (var httpClient = HttpClientFactory.CreateClient(HttpClientName)) { return await httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest { @@ -123,8 +127,10 @@ namespace Volo.Abp.IdentityModel DiscoveryDocumentResponse discoveryResponse, IdentityClientConfiguration configuration) { - using (var httpClient = HttpClientFactory.CreateClient()) + using (var httpClient = HttpClientFactory.CreateClient(HttpClientName)) { + AddHeaders(httpClient); + switch (configuration.GrantType) { case OidcConstants.GrantTypes.ClientCredentials: @@ -186,5 +192,15 @@ namespace Volo.Abp.IdentityModel return Task.CompletedTask; } + + protected virtual void AddHeaders(HttpClient client) + { + //tenantId + if (CurrentTenant.Id.HasValue) + { + //TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key + client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); + } + } } } 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..1c41727f7b 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; @@ -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/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 8fdc29ad8c..ea35628dc7 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -58,6 +58,7 @@ "404Message": "الصفحة غير موجودة", "500Message": "خطأ في الخادم الداخلي", "GoHomePage": "اذهب الى الصفحة الرئيسية", - "GoBack": "عد" + "GoBack": "عد", + "Search": "بحث" } } 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..2e4095ceae 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", @@ -54,6 +58,7 @@ "404Message": "Stránka nenalezena", "500Message": "Interní chyba serveru", "GoHomePage": "Přejít na domovskou stránku", - "GoBack": "Jít zpět" + "GoBack": "Jít zpět", + "Search": "Vyhledávání" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 77e3e37570..2bd4bc7352 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -58,6 +58,7 @@ "404Message": "Page not found", "500Message": "Internal Server Error", "GoHomePage": "Go to the homepage", - "GoBack": "Go back" + "GoBack": "Go back", + "Search" : "Search" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json index be137f013b..a7c511fe02 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json @@ -54,6 +54,7 @@ "404Message": "La página no existe", "500Message": "Error interno del servidor", "GoHomePage": "Ir a la página principal", - "GoBack": "Atras" + "GoBack": "Atras", + "Search": "Buscar" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json index b44ea3794b..6198aa360f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json @@ -58,6 +58,7 @@ "404Message": "Pagina niet gevonden", "500Message": "Interne Server Fout", "GoHomePage": "Ga naar de homepage", - "GoBack": "Ga terug" + "GoBack": "Ga terug", + "Search": "Zoeken" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index 6966b565c2..9d69ba1ef8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -54,6 +54,7 @@ "404Message": "Página não encontrada", "500Message": "Erro interno do servidor", "GoHomePage": "Voltar à página principal", - "GoBack": "Voltar" + "GoBack": "Voltar", + "Search": "Procurar" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json index 7b48db1a3a..12ccca117b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json @@ -57,6 +57,7 @@ "404Message": "Страница не найдена", "500Message": "Внутренняя ошибка сервера", "GoHomePage": "Вернуться на главную страницу", - "GoBack": "Вернуться назад" + "GoBack": "Вернуться назад", + "Search": "поиск" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json index 7fffcb73c6..2bbdb2c09d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json @@ -58,6 +58,7 @@ "404Message": "Strani ni mogoče najti", "500Message": "Napaka na strani strežnika", "GoHomePage": "Pojdi na osnovno stran", - "GoBack": "Nazaj" + "GoBack": "Nazaj", + "Search": "Iskanje" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 1369491bc4..ddf8760fa9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -58,6 +58,7 @@ "404Message": "Sayfa bulunamadı", "500Message": "Sunucu tarafında hata", "GoHomePage": "Ana sayfaya git", - "GoBack": "Geri dön" + "GoBack": "Geri dön", + "Search": "Arama" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index d1d6aa1b81..bfe84fa36b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -55,6 +55,7 @@ "404Message": "网页未找到", "500Message": "内部服务器错误", "GoHomePage": "返回主页", - "GoBack": "返回" + "GoBack": "返回", + "Search" : "搜索" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json index 7839409b4c..ae50048d03 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -54,6 +54,7 @@ "404Message": "網頁未找到", "500Message": "內部伺服器錯誤", "GoHomePage": "返回首頁", - "GoBack": "返回" + "GoBack": "返回", + "Search": "搜索" } } \ 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.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs index f401d0d6d4..3fa239ebbb 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ 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/Pages/Account/_ViewImports.cshtml b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/_ViewImports.cshtml deleted file mode 100644 index d1ac64721f..0000000000 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/_ViewImports.cshtml +++ /dev/null @@ -1,2 +0,0 @@ -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/_ViewImports.cshtml b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/_ViewImports.cshtml new file mode 100644 index 0000000000..c1da1f5f10 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@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/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..8a3aeaa5b5 100644 --- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs +++ b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs @@ -16,13 +16,13 @@ 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)); + 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)); 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/Pages/Account/_ViewImports.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/_ViewImports.cshtml index d1ac64721f..c1da1f5f10 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/_ViewImports.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/_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/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/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs index 33803c1af4..e217faf961 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.AuditLogging.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; - + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } + public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs index 3ae1d8fc10..c358bed276 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.BackgroundJobs.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs b/modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs index 9473e5274d..a7cfb4f4b6 100644 --- a/modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs +++ b/modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.BlobStoring.Database.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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..cac26eb312 100644 --- a/modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs +++ b/modules/blogging/src/Volo.Blogging.Web/BloggingMenuContributor.cs @@ -19,17 +19,16 @@ 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")); + managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Admin/Blogs")); } context.Menu.AddItem(managementRootMenuItem); diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/_ViewImports.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/_ViewImports.cshtml similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/_ViewImports.cshtml rename to modules/blogging/src/Volo.Blogging.Web/Pages/_ViewImports.cshtml 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/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs b/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs index d5fbfb4451..71824397b4 100644 --- a/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs +++ b/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Blogging.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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..803e21b805 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs +++ b/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs @@ -19,19 +19,17 @@ 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")); + rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "~/Docs/Admin/Projects")); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/_ViewImports.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/_ViewImports.cshtml new file mode 100644 index 0000000000..dd43e333dc --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/_ViewImports.cshtml @@ -0,0 +1,5 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling +@addTagHelper *, Volo.Docs.Admin.Web 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/docs/test/Volo.Docs.MongoDB.Tests/Volo/Docs/MongoDB/MongoDbFixture.cs b/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo/Docs/MongoDB/MongoDbFixture.cs index fc920813ab..9a40d79492 100644 --- a/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo/Docs/MongoDB/MongoDbFixture.cs +++ b/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo/Docs/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Docs.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs index bfd7fa9c04..bb89a83f76 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.FeatureManagement.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs index def41cdc8a..bf698ca54f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs @@ -64,9 +64,20 @@ namespace Volo.Abp.Identity bool includeDetails = false, CancellationToken cancellationToken = default ); + Task GetMembersCountAsync( OrganizationUnit organizationUnit, CancellationToken cancellationToken = default ); + + Task RemoveAllRolesAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default + ); + + Task RemoveAllMembersAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default + ); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs index f90694349a..2400743ab3 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs @@ -96,7 +96,6 @@ namespace Volo.Abp.Identity return IdentityResult.Success; } - public virtual async Task IsInOrganizationUnitAsync(Guid userId, Guid ouId) { var user = await IdentityUserRepository.GetAsync(userId, cancellationToken: CancellationToken); @@ -191,12 +190,13 @@ namespace Volo.Abp.Identity } [UnitOfWork] - public virtual async Task> GetOrganizationUnitsAsync(IdentityUser user) + public virtual async Task> GetOrganizationUnitsAsync(IdentityUser user, bool includeDetails = false) { await IdentityUserRepository.EnsureCollectionLoadedAsync(user, u => u.OrganizationUnits, CancellationTokenProvider.Token); return await OrganizationUnitRepository.GetListAsync( user.OrganizationUnits.Select(t => t.OrganizationUnitId), + includeDetails, cancellationToken: CancellationToken ); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs index bfaa522dd0..778bde3802 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs @@ -77,9 +77,15 @@ namespace Volo.Abp.Identity foreach (var child in children) { + await OrganizationUnitRepository.RemoveAllMembersAsync(child); + await OrganizationUnitRepository.RemoveAllRolesAsync(child); await OrganizationUnitRepository.DeleteAsync(child); } + var organizationUnit = await OrganizationUnitRepository.GetAsync(id); + + await OrganizationUnitRepository.RemoveAllMembersAsync(organizationUnit); + await OrganizationUnitRepository.RemoveAllRolesAsync(organizationUnit); await OrganizationUnitRepository.DeleteAsync(id); } @@ -133,7 +139,7 @@ namespace Volo.Abp.Identity { if (!recursive) { - return await OrganizationUnitRepository.GetChildrenAsync(parentId); + return await OrganizationUnitRepository.GetChildrenAsync(parentId, includeDetails: true); } if (!parentId.HasValue) @@ -143,7 +149,7 @@ namespace Volo.Abp.Identity var code = await GetCodeOrDefaultAsync(parentId.Value); - return await OrganizationUnitRepository.GetAllChildrenWithParentCodeAsync(code, parentId); + return await OrganizationUnitRepository.GetAllChildrenWithParentCodeAsync(code, parentId, includeDetails: true); } public virtual Task IsInOrganizationUnitAsync(IdentityUser user, OrganizationUnit ou) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index c1bee0449a..9ad8effa8a 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -41,7 +41,14 @@ namespace Volo.Abp.Identity.EntityFrameworkCore where userRole.UserId == id select role.Name; var organizationUnitIds = DbContext.Set().Where(q => q.UserId == id).Select(q => q.OrganizationUnitId).ToArray(); - var organizationRoleIds = DbContext.Set().Where(our => organizationUnitIds.Contains(our.OrganizationUnitId)).Select(r => r.RoleId).ToArray(); + + var organizationRoleIds = await ( + from ouRole in DbContext.Set() + join ou in DbContext.Set() on ouRole.OrganizationUnitId equals ou.Id + where organizationUnitIds.Contains(ouRole.OrganizationUnitId) + select ouRole.RoleId + ).ToListAsync(GetCancellationToken(cancellationToken)); + var orgUnitRoleNameQuery = DbContext.Roles.Where(r => organizationRoleIds.Contains(r.Id)).Select(n => n.Name); var resultQuery = query.Union(orgUnitRoleNameQuery); return await resultQuery.ToListAsync(GetCancellationToken(cancellationToken)); @@ -53,11 +60,14 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { var query = from userOu in DbContext.Set() join roleOu in DbContext.Set() on userOu.OrganizationUnitId equals roleOu.OrganizationUnitId + join ou in DbContext.Set() on roleOu.OrganizationUnitId equals ou.Id join userOuRoles in DbContext.Roles on roleOu.RoleId equals userOuRoles.Id where userOu.UserId == id select userOuRoles.Name; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + var result = await query.ToListAsync(GetCancellationToken(cancellationToken)); + + return result; } public virtual async Task FindByLoginAsync( @@ -152,15 +162,16 @@ namespace Volo.Abp.Identity.EntityFrameworkCore where userOrg.UserId == id select ou; - var orgUserRoleQuery = DbContext.Set().Where(q => userOrganizationsQuery.Select(t => t.Id).Contains(q.OrganizationUnitId)) + var orgUserRoleQuery = DbContext.Set() + .Where(q => userOrganizationsQuery + .Select(t => t.Id) + .Contains(q.OrganizationUnitId)) .Select(t => t.RoleId); var orgRoles = DbContext.Roles.Where(q => orgUserRoleQuery.Contains(q.Id)); var resultQuery = query.Union(orgRoles); return await resultQuery.ToListAsync(GetCancellationToken(cancellationToken)); - - //return await query.ToListAsync(GetCancellationToken(cancellationToken)); } public virtual async Task GetCountAsync( @@ -201,22 +212,18 @@ namespace Volo.Abp.Identity.EntityFrameworkCore where userOu.OrganizationUnitId == organizationUnitId select user; return await query.ToListAsync(GetCancellationToken(cancellationToken)); - } - - public async Task> GetUsersInOrganizationsListAsync( - List organizationUnitIds, - CancellationToken cancellationToken = default - ) - { - //var userIds = DbContext.Set() - // .Where(q => organizationUnitIds.Contains(q.OrganizationUnitId)) - // .Select(u => u.UserId); - //var query = DbContext.Users.Where(u => userIds.Contains(u.Id)); + } + + public async Task> GetUsersInOrganizationsListAsync( + List organizationUnitIds, + CancellationToken cancellationToken = default + ) + { var query = from userOu in DbContext.Set() join user in DbSet on userOu.UserId equals user.Id where organizationUnitIds.Contains(userOu.OrganizationUnitId) select user; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + return await query.ToListAsync(GetCancellationToken(cancellationToken)); } public virtual async Task> GetUsersInOrganizationUnitWithChildrenAsync( @@ -235,6 +242,6 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); - } + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs index 350f64ffe7..06b2084707 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs @@ -102,7 +102,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public virtual async Task GetRolesCountAsync( OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) - { + { var query = from organizationRole in DbContext.Set() join role in DbContext.Roles on organizationRole.RoleId equals role.Id where organizationRole.OrganizationUnitId == organizationUnit.Id @@ -156,5 +156,24 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { return GetQueryable().IncludeDetails(); } + + public virtual Task RemoveAllRolesAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default) + { + organizationUnit.Roles.Clear(); + return Task.CompletedTask; + } + + public virtual async Task RemoveAllMembersAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default) + { + var ouMembersQuery = await DbContext.Set() + .Where(q => q.OrganizationUnitId == organizationUnit.Id) + .ToListAsync(GetCancellationToken(cancellationToken)); + + DbContext.Set().RemoveRange(ouMembersQuery); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs index ae735300fd..943d570153 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs @@ -1,17 +1,22 @@ -using MongoDB.Driver; +using MongoDB.Bson; +using MongoDB.Driver; using MongoDB.Driver.Linq; using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; +using Volo.Abp.Uow; namespace Volo.Abp.Identity.MongoDB { - public class MongoOrganizationUnitRepository : MongoDbRepository, IOrganizationUnitRepository + public class MongoOrganizationUnitRepository + : MongoDbRepository, + IOrganizationUnitRepository { public MongoOrganizationUnitRepository( IMongoDbContextProvider dbContextProvider) @@ -134,5 +139,25 @@ namespace Volo.Abp.Identity.MongoDB .As>() .CountAsync(GetCancellationToken(cancellationToken)); } + + public virtual Task RemoveAllRolesAsync(OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) + { + organizationUnit.Roles.Clear(); + return Task.FromResult(0); + } + + public virtual async Task RemoveAllMembersAsync(OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) + { + var users = await DbContext.Users.AsQueryable() + .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) + .As>() + .ToListAsync(GetCancellationToken(cancellationToken)); + + foreach (var user in users) + { + user.RemoveOrganizationUnit(organizationUnit.Id); + DbContext.Users.ReplaceOne(u => u.Id == user.Id, user); + } + } } } 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..279ea16278 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs @@ -16,31 +16,28 @@ 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); if (hasRolePermission) { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "/Identity/Roles")); + identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "~/Identity/Roles")); } if (hasUserPermission) { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "/Identity/Users")); + identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "~/Identity/Users")); } } } } -} \ 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/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/MongoDbFixture.cs b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/MongoDbFixture.cs index 26de0a9399..09581c13d5 100644 --- a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/MongoDbFixture.cs +++ b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.Identity.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs index 6f6835396d..5ff0284194 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs @@ -151,5 +151,37 @@ namespace Volo.Abp.Identity rolesCount.ShouldBeGreaterThan(1); } + + [Fact] + public async Task RemoveAllMembersOfOrganizationUnit() + { + OrganizationUnit ou = await _organizationUnitRepository.GetAsync("OU111", true); + var membersCount = await _organizationUnitRepository.GetMembersCountAsync(ou); + membersCount.ShouldBeGreaterThan(1); + + await _organizationUnitRepository.RemoveAllMembersAsync(ou); + var newCount = await _organizationUnitRepository.GetMembersCountAsync(ou); + newCount.ShouldBe(0); + } + + [Fact] + public async Task RemoveAllRolesOfOrganizationUnit() + { + using (var uow = _unitOfWorkManager.Begin()) + { + OrganizationUnit ou = await _organizationUnitRepository.GetAsync("OU111", true); + var rolesCount = await _organizationUnitRepository.GetRolesCountAsync(ou); + rolesCount.ShouldBeGreaterThan(1); + + await _organizationUnitRepository.RemoveAllRolesAsync(ou); + + await uow.SaveChangesAsync(); + + var newCount = await _organizationUnitRepository.GetRolesCountAsync(ou); + newCount.ShouldBe(0); + + await uow.CompleteAsync(); + } + } } } 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/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/MongoDbFixture.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/MongoDbFixture.cs index 22bbf08ef4..2c2f120acd 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/MongoDbFixture.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.IdentityServer { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ 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/Pages/AbpPermissionManagement/_ViewImports.cshtml b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/_ViewImports.cshtml index d1ac64721f..c1da1f5f10 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/_ViewImports.cshtml +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/_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/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/permission-management-modal.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/permission-management-modal.js index b8bef0b7d1..860d6f8bfb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/permission-management-modal.js +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/permission-management-modal.js @@ -35,18 +35,44 @@ }); } + function handleTabCheckedCheckboxCount($tab) { + var newCount = 0; + $tab.find('input[type="checkbox"]').not('[name="SelectAllInThisTab"]').each(function () { + if ($(this).is(':checked') === true) { + newCount++; + } + }); + + var $tabTitle = $('#' + $tab.attr('id') + '-tab'); + var title = $tabTitle.html() + .replace('','').replace('','') + .replace('','').replace('',''); + + var titleSplitted = title.split(' '); + if (titleSplitted[titleSplitted.length-1].startsWith('(')){ + titleSplitted.pop(); + } + var titleWithoutCount = titleSplitted.join(' '); + var newTitle = titleWithoutCount + ' (' + (newCount) + ')'; + if (newCount > 0){ + newTitle = '' + newTitle + '' + } + else { + newTitle = '' + newTitle + '' + } + $tabTitle.html(newTitle) + }; + function handleUncheck($tab) { var $checkBox = $tab.find('input[name="SelectAllInThisTab"]'); if ($checkBox.is(':checked')) { if ($tab.find('input[type="checkbox"]').not('[name="SelectAllInThisTab"]').length > 1) { $($checkBox).prop('indeterminate', true); - } - else { + } else { $checkBox.prop('checked', false); } - } - else if ($checkBox.is(':indeterminate')) { + } else if ($checkBox.is(':indeterminate')) { var allUnchecked = true; $tab.find('input[type="checkbox"]').not('[name="SelectAllInThisTab"]').each(function () { @@ -76,12 +102,12 @@ if (allChecked) { $($checkBox).prop('indeterminate', false); $checkBox.prop('checked', true); - } - else { + } else { $($checkBox).prop('indeterminate', true); } } + function initSelectAllInThisTab() { var tabs = $('.tab-pane'); for (var i = 0; i < tabs.length; i++) { @@ -101,11 +127,9 @@ if (allChecked) { $($checkBox).prop('checked', true); - } - else if (allUnChecked) { + } else if (allUnChecked) { $($checkBox).prop('checked', false); - } - else { + } else { $($checkBox).prop('indeterminate', true); } } @@ -139,11 +163,9 @@ if (allChecked) { $($checkBox).prop('checked', true); - } - else if (allUnChecked) { + } else if (allUnChecked) { $($checkBox).prop('checked', false); - } - else { + } else { $($checkBox).prop('indeterminate', true); } } @@ -151,6 +173,7 @@ this.initDom = function ($el) { $el.find('.tab-pane').each(function () { var $tab = $(this); + handleTabCheckedCheckboxCount($tab); $tab.find('input[type="checkbox"]').not('[name="SelectAllInThisTab"]').each(function () { var $checkBox = $(this); $checkBox.change(function () { @@ -162,6 +185,7 @@ handleUncheck($tab); } setSelectAllInAllTabs(); + handleTabCheckedCheckboxCount($tab); }); }); }); @@ -176,6 +200,7 @@ } $($checkBox).prop('indeterminate', false); setSelectAllInAllTabs(); + handleTabCheckedCheckboxCount($tab) }); $('input[name="SelectAllInAllTabs"]').change(function () { @@ -186,6 +211,10 @@ $('.tab-pane input[type="checkbox"]').not(':disabled').prop('checked', false); } $($checkBox).prop('indeterminate', false); + + $el.find('.tab-pane').each(function () { + handleTabCheckedCheckboxCount($(this)) + }); }); $(function () { @@ -201,4 +230,4 @@ setSelectAllInAllTabs(); }; }; -})(jQuery); \ No newline at end of file +})(jQuery); 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/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbFixture.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbFixture.cs index 3a09e6e1a4..97799fc03b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbFixture.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.PermissionManagement.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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..20946c09ea 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() @@ -37,7 +37,7 @@ namespace Volo.Abp.SettingManagement.Web.Navigation new ApplicationMenuItem( SettingManagementMenuNames.GroupName, l["Settings"], - "/SettingManagement", + "~/SettingManagement", icon: "fa fa-cog" ) ); 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/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo/Abp/SettingManagement/MongoDB/MongoDbFixture.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo/Abp/SettingManagement/MongoDB/MongoDbFixture.cs index 31ccdcc4f7..4f9142a829 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo/Abp/SettingManagement/MongoDB/MongoDbFixture.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo/Abp/SettingManagement/MongoDB/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.SettingManagement.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} 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..0a36e9d130 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,15 +18,14 @@ 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")); + 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/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo/Abp/TenantManagement/MongoDb/MongoDbFixture.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo/Abp/TenantManagement/MongoDb/MongoDbFixture.cs index be115d9dff..1b3777f6a8 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo/Abp/TenantManagement/MongoDb/MongoDbFixture.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo/Abp/TenantManagement/MongoDb/MongoDbFixture.cs @@ -5,12 +5,18 @@ namespace Volo.Abp.TenantManagement.MongoDB { public class MongoDbFixture : IDisposable { - private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); - public static readonly string ConnectionString = MongoDbRunner.ConnectionString; + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } public void Dispose() { MongoDbRunner?.Dispose(); } } -} \ No newline at end of file +} diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs index 7f0f5620db..a54790410e 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs @@ -1,5 +1,6 @@ namespace Volo.Abp.Users.MongoDB { + [Collection(MongoTestCollection.Name)] public class AbpUserRepository_Tests : AbpUserRepository_Tests { diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs index a2235ee03e..560d6287d7 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs @@ -16,9 +16,9 @@ namespace Volo.Abp.Users.MongoDB public override void ConfigureServices(IServiceCollection services) { - var connectionString = MongoDbRunner.ConnectionString.EnsureEndsWith('/') + + var connectionString = MongoDbFixture.ConnectionString.EnsureEndsWith('/') + "Db_" + - Guid.NewGuid().ToString("N"); + Guid.NewGuid().ToString("N"); Configure(options => { diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs index 451ef8baae..764cadedf4 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs @@ -1,7 +1,8 @@ namespace Volo.Abp.Users.MongoDB { + [Collection(MongoTestCollection.Name)] public class ExternalUserLookupService_Tests : ExternalUserLookupService_Tests { - + } -} \ No newline at end of file +} diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs index 26f9aa1ac5..b52af21d3e 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs @@ -1,7 +1,8 @@ namespace Volo.Abp.Users.MongoDB { + [Collection(MongoTestCollection.Name)] public class LocalUserLookupService_Tests : LocalUserLookupService_Tests { - + } -} \ No newline at end of file +} diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoDbFixture.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoDbFixture.cs new file mode 100644 index 0000000000..4f8c6eea2f --- /dev/null +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoDbFixture.cs @@ -0,0 +1,22 @@ +using System; +using Mongo2Go; + +namespace Volo.Abp.Users.MongoDB +{ + public class MongoDbFixture : IDisposable + { + private static readonly MongoDbRunner MongoDbRunner; + public static readonly string ConnectionString; + + static MongoDbFixture() + { + MongoDbRunner = MongoDbRunner.Start(); + ConnectionString = MongoDbRunner.ConnectionString; + } + + public void Dispose() + { + MongoDbRunner?.Dispose(); + } + } +} diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoTestCollection.cs b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoTestCollection.cs new file mode 100644 index 0000000000..d8b6a718d8 --- /dev/null +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoTestCollection.cs @@ -0,0 +1,10 @@ +using Xunit; + +namespace Volo.Abp.Users.MongoDB +{ + [CollectionDefinition(Name)] + public class MongoTestCollection : ICollectionFixture + { + public const string Name = "MongoDB Collection"; + } +} diff --git a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Volo.Abp.VirtualFileExplorer.DemoApp.csproj b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Volo.Abp.VirtualFileExplorer.DemoApp.csproj index b1a9bbb18c..fcf92ef6b8 100644 --- a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Volo.Abp.VirtualFileExplorer.DemoApp.csproj +++ b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Volo.Abp.VirtualFileExplorer.DemoApp.csproj @@ -1,7 +1,5 @@  - - netcoreapp3.1 aspnet-Volo.Abp.VirtualFileExplorer.DemoApp-234AF9E1-C3E0-4F8F-BD7D-840627CC8E46 diff --git a/modules/virtual-file-explorer/common.props b/modules/virtual-file-explorer/common.props deleted file mode 100644 index 4adb69f0fe..0000000000 --- a/modules/virtual-file-explorer/common.props +++ /dev/null @@ -1,12 +0,0 @@ - - - latest - 0.1.0 - $(NoWarn);CS1591 - - - - - - - \ No newline at end of file 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..5555a054f5 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,9 +15,9 @@ 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")); + context.Menu.Items.Add(new ApplicationMenuItem(VirtualFileExplorerMenuNames.Index, l["Menu:VirtualFileExplorer"], icon: "fa fa-file", url: "~/VirtualFileExplorer")); return Task.CompletedTask; } 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($"