diff --git a/.github/ISSUE_TEMPLATE/02_feature_request.yml b/.github/ISSUE_TEMPLATE/02_feature_request.yml index 21189e3a30..029830c7c5 100644 --- a/.github/ISSUE_TEMPLATE/02_feature_request.yml +++ b/.github/ISSUE_TEMPLATE/02_feature_request.yml @@ -1,6 +1,6 @@ name: 💡 Feature request description: Suggest an idea for this project -labels: [feature] +labels: [feature-request] body: - type: checkboxes attributes: diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..43e9cba5de --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 7.x.x | :white_check_mark: | +| < 7.0.0 | :x: | + +## Reporting a Vulnerability + +Please don not share vulnerabilities publicly in GitHub or other platforms. +You can report security issues by sending a email to `security@abp.io` +Your report is immediately evaluated. We publish patch versions for critical vulnerabilities in a week at most. diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json index 4a7e64125f..d3537d3742 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json @@ -167,7 +167,7 @@ "ABPDiscordServer": "ABP سيرفر الدسكورد", "ABPCommunityTalks": "برامج منتدى ABP الحوارية", "ABPCommunityPosts": "منشورات منتدى ABP", - "BuyAndGetMonths": "شراء 12 شهر، احصل على 14 شهرا!", + "BuyAndGetMonths": "شراء 12 شهر، احصل على 14 شهرا!", "GetYourDeal": "احصل على صفقتك", "BuyOrRenewLicense": "اشترِ أو جدد الرخصة الآن واحصل على شهرين إضافيين!", "BuyOrRenewLicenseToGetExtra2Months": "اشترِ أو جدد الرخصة الآن واحصل على شهرين إضافيين! اسرع! ⏰ آخر يوم: {0}", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 9ef432a8bd..63f78103d9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -171,7 +171,7 @@ "ABPDiscordServer": "ABP Discord Server", "ABPCommunityTalks": "ABP Community Talks", "ABPCommunityPosts": "ABP Community Posts", - "BuyAndGetMonths": "BUY 12 MONTHS, GET 14 MONTHS!", + "BuyAndGetMonths": "BUY 12 MONTHS, GET 14 MONTHS!", "GetYourDeal": "Get Your Deal", "BuyOrRenewLicense": "Buy or Renew License Now and Get 2 Extra Months!", "BuyOrRenewLicenseToGetExtra2Months": "Buy or Renew License Now and Get 2 Extra Months! HURRY UP! ⏰ Last Day: {0}", @@ -187,7 +187,7 @@ "GiveAwayForNewPurchases": "Application Development Classroom Training will be given away for the new purchases!", "BlackFriday": "BLACK FRIDAY", "ValidForExistingCustomers": "Also valid for the
existing customers!", - "CampaignBetweenDates": "From {0}
to {1}", + "CampaignBetweenDates": "From {0}
To {1}", "SaveUpTo": "SAVE UP TO${0}K", "ImplementingDDD": "Implementing Domain Driven Design", "ExploreTheEBook": "Explore the E-Book", @@ -220,6 +220,7 @@ "NoContent": "No content", "More": "More", "WhyABPIOPlatform": "Why ABP.IO Platform?", - "AbpStudio": "ABP Studio" + "AbpStudio": "ABP Studio", + "ExtraMonths": "{0}EXTRA MONTHS" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json index 16437480ef..80f351043f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json @@ -170,7 +170,7 @@ "ABPDiscordServer": "ABP Discord-palvelin", "ABPCommunityTalks": "ABP Community Talks", "ABPCommunityPosts": "ABP-yhteisön viestit", - "BuyAndGetMonths": "OSTA 12 KUUKAUTA, SAAT 14 KUUKAUTA!", + "BuyAndGetMonths": "OSTA 12 KUUKAUTA, SAAT 14 KUUKAUTA!", "GetYourDeal": "Hanki tarjouksesi", "BuyOrRenewLicense": "Osta tai uusi lisenssi nyt ja saat 2 lisäkuukautta!", "BuyOrRenewLicenseToGetExtra2Months": "Osta tai uusi lisenssi nyt ja saat 2 lisäkuukautta! KIIREHDI! ⏰ Viimeinen päivä: {0}", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json index b9ccddecf4..d785f418aa 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json @@ -168,7 +168,7 @@ "ABPDiscordServer": "ABP Discord szerver", "ABPCommunityTalks": "ABP közösségi beszélgetések", "ABPCommunityPosts": "ABP közösségi bejegyzések", - "BuyAndGetMonths": "VÁSÁROLJON 12 HÓNAPOT, 14 HÓNAPOT KAP!", + "BuyAndGetMonths": "VÁSÁROLJON 12 HÓNAPOT, 14 HÓNAPOT KAP!", "GetYourDeal": "Szerezze meg az ajánlatát", "BuyOrRenewLicense": "Vásároljon vagy újítson meg licencet most, és 2 további hónapot kap!", "BuyOrRenewLicenseToGetExtra2Months": "Vásároljon vagy újítson meg licencet most, és 2 további hónapot kap! SIESS! ⏰ Utolsó nap: {0}", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json index d1a0db7176..545a909abf 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json @@ -170,7 +170,7 @@ "ABPDiscordServer": "ABP Discord 服务器", "ABPCommunityTalks": "ABP社区讲话", "ABPCommunityPosts": "ABP社区文章", - "BuyAndGetMonths": "购买 12 个月,获得 14 个月!", + "BuyAndGetMonths": "购买 12 个月,获得 14 个月!", "GetYourDeal": "得到你的交易", "BuyOrRenewLicense": "立即购买或续订许可证并额外获得 2 个月!", "BuyOrRenewLicenseToGetExtra2Months": "立即购买或续订 ABP 商业许可证(适用于所有版本)并额外获得 2 个月!", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 1b8c972d5c..d9794a06e4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -567,7 +567,7 @@ "TotalPrice": "Total Price", "ThereIsNoInvoice": "There is no invoice", "MyOrganizations_Detail_PaymentProviderInfo": "If you have purchased your license through {0} gateway, it sends the PDF invoice to your email address, see {0} invoicing.", - "MyOrganizations_Detail_PayUInfo": "If you have purchased through the PayU gateway, click the \"Request Invoice\" button and fill in the billing information.", + "MyOrganizations_Detail_PayUInfo": "If you have purchased through the Iyzico gateway, click the \"Request Invoice\" button and fill in the billing information.", "MyOrganizations_Detail_ConclusionInfo": "Your invoice request will be concluded within {0} business days.", "ExtendYourLicense": "Extend your {0} license", "Continue": "Continue", @@ -1001,19 +1001,19 @@ "ABPSOLUTION": "ABP SOLUTION", "CreatingAnEmptySolution_ABPSOLUTION_Description": "ABP provides a well-architected, layered and production-ready startup solution based on the Domain Driven Design principles. The solution also includes a pre-configured unit and integration test projects for each layer.", "CommonLibraries": "Common Libraries", - "CommonLibraries_THEPROBLEM_Description": "Which libraries should you use to implement common requirements? The software development ecosystem is highly dynamic and it is hard to follow the latest tools, libraries, trends and approaches.", - "CommonLibraries_ABPSOLUTION_Description": "ABP pre-integrates the popular, mature and up-to-date libraries into the solution. You don't spend time integrating them and talking to each other. They properly work out of the box.", + "CommonLibraries_THEPROBLEM_Description": "Which libraries should you use to implement common requirements? The software development ecosystem is highly dynamic, making it challenging to keep up with the latest tools, libraries, trends, and approaches.", + "CommonLibraries_ABPSOLUTION_Description": "ABP pre-integrates popular, mature, and up-to-date libraries into the solution. You don't need to spend time integrating them or making them communicate with each other. They work properly out of the box.", "UITheme&Layout": "UI Theme & Layout", - "UITheme&Layout_THEPROBLEM_Description": "When it comes to the UI, there are a lot of challenges, including preparing a foundation to create a responsive, modern and flexible UI kit with a consistent look & feel and tons of features (like left/top navigation menu, header, toolbar, footer, widgets and so.).", - "UITheme&Layout_THEPROBLEM_Description2": "Even if you buy a pre-built theme, integrating it into your solution may take days of development. Upgrading such a theme is another problem. Most of the time, the theme's HTML/CSS structure is mixed with your UI code, and it is not easy to upgrade or change the theme later.", - "UITheme&Layout_ABPSOLUTION_Description": "ABP Framework provides a theming system that makes your UI code independent from the theme. Themes are isolated, and they are NuGet/NPM packages. Installing or upgrading a theme is just a minute. While you can build your theme (or integrate an existing theme), ABP Commercial offers professional and modern themes.", - "UITheme&Layout_ABPSOLUTION_Description2": "There are also UI component providers (like Telerik and DevExpress). But they only provide individual components. You are responsible for creating your own layout system. You can use such libraries in your ABP-based solutions just like in any other project.", + "UITheme&Layout_THEPROBLEM_Description": "When addressing UI concerns, a range of challenges surfaces. These include establishing the groundwork for a responsive, contemporary, and adaptable UI kit with a consistent appearance and a host of features like navigation menus, headers, toolbars, footers, widgets, and more.", + "UITheme&Layout_THEPROBLEM_Description2": "Even if you opt for a pre-designed theme, seamlessly integrating it into your project could demand days of development. An additional hurdle lies in upgrading such themes. Frequently, the theme's HTML/CSS structure becomes intertwined with your UI code, rendering future theme changes or upgrades intricate tasks. This interweaving of code and design complicates the flexibility of making adjustments down the line.", + "UITheme&Layout_ABPSOLUTION_Description": "ABP Framework offers a distinctive theming system that liberates your UI code from theme constraints. Themes exist in isolation, packaged as NuGet or NPM packages, making theme installation or upgrades a matter of minutes. While you retain the option to develop your custom theme or integrate an existing one, ABP Commercial presents a collection of polished and contemporary themes.", + "UITheme&Layout_ABPSOLUTION_Description2": "Additionally, there are UI component providers like Telerik and DevExpress. However, these providers primarily furnish individual components, placing the onus on you to establish your layout system. When working within ABP-based projects, you can seamlessly incorporate these libraries, similar to how you would in any other project.", "TestInfrastructure": "Test Infrastructure", - "TestInfrastructure_THEPROBLEM_Description": "Preparing a robust test environment takes time. You need to setup test projects in your solution, select the tools, mock the services and database, create the required base classes and utility services to reduce repeating code in the tests and so on.", - "TestInfrastructure_ABPSOLUTION_Description": "ABP Startup Templates comes with the test projects already configured for you, and you can immediately write your first unit or integration test code on day 1.", + "TestInfrastructure_THEPROBLEM_Description": "Establishing a robust testing environment is a time-consuming endeavor. It involves setting up dedicated test projects within your solution, carefully selecting the necessary tools, creating service and database mocks, crafting essential base classes and utility services to minimize redundant code across tests, and addressing various related tasks.", + "TestInfrastructure_ABPSOLUTION_Description": "ABP Startup Templates arrive pre-equipped with configured test projects, streamlining the process for you. This means that from day one, you can readily commence writing your initial unit or integration test code without delay.", "CodingStandards&Training": "Coding Standards & Training", - "CodingStandards&Training_THEPROBLEM_Description": "Once you create the development-ready solution, you typically need to train the developers to explain the system and develop it with the same conventions in a standard and consistent way. Even if you train the developers, it is hard to prepare and maintain your documentation. Over time, every developer will write the code differently, and coding standards will begin to diverge.", - "CodingStandards&Training_ABPSOLUTION_Description": "ABP solution is already well-defined and well-documented. Tutorials and best practice guides clearly explain how to make development on an ABP project.", + "CodingStandards&Training_THEPROBLEM_Description": "After you've set up the solution for development, you usually have to teach the developers how the system works and how to build it using the same agreed-upon methods. Even if you give them training, keeping the documentation up-to-date can be difficult. As time goes on, each developer might write code in their own way, causing the rules for writing code to become different from each other.", + "CodingStandards&Training_ABPSOLUTION_Description": "The ABP solution is already neatly organized and has clear explanations. Step-by-step tutorials and guides show you exactly how to work on an ABP project.", "KeepingYourSolutionUpToDate": "Keeping Your Solution Up to Date", "KeepingYourSolutionUpToDate_THEPROBLEM_Description": "After you start your development, you must keep track of the new versions of the libraries you use for upgrades & patches.", "KeepingYourSolutionUpToDate_ABPSOLUTION_Description": "We regularly update all packages to the latest versions and test them before the stable release. When you update the ABP Framework, all its dependencies are upgraded to edge technology.", @@ -1073,6 +1073,8 @@ "ABPCommunity_Description2": "It is easy to share code or even re-usable libraries between ABP developers. A code snippet that works for you will also work for others. There are a lot of samples and tutorials that you can directly implement for your application.", "ABPCommunity_Description3": "When you hire a developer who worked before with the ABP architecture will immediately understand your solution and start development in a very short time.", "WhyAbpIo_Page_Title": "Why ABP.IO Platform?", - "AbpStudio_Page_Title": "ABP Studio" + "AbpStudio_Page_Title": "ABP Studio", + "CampaignInfo": "Buy a new license or renew your existing license and get an additional 2 months at no additional cost! This offer is valid for all license plans. Ensure you take advantage of this limited-time promotion to expand your access to premium features and upgrades.", + "HurryUpLastDay": "Hurry Up! Last Day: {0}" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index e6b3cf46f7..4951ee85b4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -37,6 +37,7 @@ "ThisExtensionIsNotAllowed": "This extension is not allowed.", "TheFileIsTooLarge": "The file is too large.", "GoToThePost": "Go to the Post", + "GoToTheVideo": "Go to the Video", "Contribute": "Contribute", "OverallProgress": "Overall Progress", "Done": "Done", @@ -189,6 +190,7 @@ "SeeMoreVideos": "See more videos", "DiscordPageTitle": "ABP Discord Community", "ViewVideo": "View Video", - "AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework" + "AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework", + "CommunitySlogan": "A unique community platform for ABP Lovers" } } diff --git a/common.props b/common.props index ea9b36f855..e956b17835 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 7.4.0-rc.3 + 8.0.0 $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/POST.md b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/POST.md new file mode 100644 index 0000000000..c7d8411886 --- /dev/null +++ b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/POST.md @@ -0,0 +1,287 @@ +# ABP.IO Platform 7.4 RC Has Been Released + +Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **7.4 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version. + +Try this version and provide feedback for a more stable version of ABP v7.4! Thanks to all of you. + +## Get Started with the 7.4 RC + +Follow the steps below to try version 7.4.0 RC today: + +1) **Upgrade** the ABP CLI to version `7.4.0-rc.1` using a command line terminal: + +````bash +dotnet tool update Volo.Abp.Cli -g --version 7.4.0-rc.1 +```` + +**or install** it if you haven't before: + +````bash +dotnet tool install Volo.Abp.Cli -g --version 7.4.0-rc.1 +```` + +2) Create a **new application** with the `--preview` option: + +````bash +abp new BookStore --preview +```` + +See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options. + +> You can also use the [Get Started](https://abp.io/get-started) page to generate a CLI command to create a new application. + +You can use any IDE that supports .NET 7.x, like [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/). + +## Migration Guides + +There are a few breaking changes in this version that may affect your application. +Please see the following migration documents, if you are upgrading from v7.3 or earlier: + +* [ABP Framework 7.3 to 7.4 Migration Guide](https://docs.abp.io/en/abp/7.4/Migration-Guides/Abp-7_4) + +## What's New with ABP Framework 7.4? + +In this section, I will introduce some major features released in this version. Here is a brief list of the titles that will be explained in the next sections: + +* Dynamic Setting Store +* Introducing the `AdditionalAssemblyAttribute` +* `CorrelationId` Support on Distributed Events +* Database Migration System for EF Core +* Other News + +### Dynamic Setting Store + +Prior to this version, it was hard to define settings in different microservices and centrally manage all setting definitions in a single admin application. To make that possible, we used to add project references for all the microservices' service contract packages from a single microservice, so it can know all the setting definitions and manage them. + +In this version, ABP Framework introduces the Dynamic Setting Store, which is an important feature that allows you to collect and get all setting definitions from a single point and overcome the setting management problems on microservices. + +> *Note*: If you are upgrading from an earlier version and using the Setting Management module, you need to create a new migration and apply it to your database because a new database table has been added for this feature. + +### Introducing the `AdditionalAssemblyAttribute` + +In this version, we have introduced the `AdditionalAssemblyAttribute` to define additional assemblies to be part of a module. ABP Framework automatically registers all the services of your module to the [Dependency Injection System](https://docs.abp.io/en/abp/latest/Dependency-Injection). It finds the service types by scanning types in the assembly that define your module class. Typically, every assembly contains a separate module class definition and modules depend on each other using the `DependsOn` attribute. + +In some rare cases, your module may consist of multiple assemblies and only one of them defines a module class, and you want to make the other assemblies parts of your module. This is especially useful if you can't define a module class in the target assembly or you don't want to depend on that module's dependencies. + +In that case, you can use the `AdditionalAssembly` attribute as shown below: + +```csharp +[DependsOn(...)] // Your module dependencies as you normally would do +[AdditionalAssembly(typeof(IdentityServiceModule))] // A type in the target assembly (in another assembly) +public class IdentityServiceTestModule : AbpModule +{ + ... +} +``` + +With the `AdditionalAssembly` attribute definition, ABP loads the assembly containing the `IdentityServiceModule` class as a part of the identity service module. Notice that in this case, none of the module dependencies of the `IdentityServiceModule` are loaded. Because we are not depending on the `IdentityServiceModule`, instead we are just adding its assembly as a part of the `IdentityServiceTestModule`. + +> You can check the [Module Development Basics](https://docs.abp.io/en/abp/7.4/Module-Development-Basics) documentation to learn more. + +### `CorrelationId` Support on Distributed Events + +In this version, `CorrelationId` (a unique key that is used in distributed applications to trace requests across multiple services/operations) is attached to the distributed events, so you can relate events with HTTP requests and can trace all the related activities. + +ABP Framework generates a `correlationId` for the first time when an operation is started and then attaches the current `correlationId` to distributed events as an additional property. For example, if you are using the [transactional outbox or inbox pattern provided by ABP Framework](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus#outbox-inbox-for-transactional-events), you can see the `correlationId` in the extra properties of the `IncomingEventInfo` or `OutgoingEventInfo` classes with the standard `X-Correlation-Id` key. + +> You can check [this issue](https://github.com/abpframework/abp/issues/16773) for more information. + +### Database Migration System for EF Core + +In this version, ABP Framework provides base classes and events to migrate the database schema and seed the database on application startup. This system works compatibly with multi-tenancy and whenever a new tenant is created or a tenant's database connection string has been updated, it checks and applies database migrations for the new tenant state. + +This system is especially useful to migrate databases for microservices. In this way, when you deploy a new version of a microservice, you don't need to manually migrate its database. + +You need to take the following actions to use the database migration system: + +* Create a class that derives from `EfCoreRuntimeDatabaseMigratorBase` class, override and implement its `SeedAsync` method. And lastly, execute the `CheckAndApplyDatabaseMigrationsAsync` method of your class in the `OnPostApplicationInitializationAsync` method of your module class. +* Create a class that derives from `DatabaseMigrationEventHandlerBase` class, override and implement its `SeedAsync` method. Then, whenever a new tenant is created or a tenant's connection string is changed then the `SeedAsync` method will be executed. + +### Other News + +* [OpenIddict](https://github.com/openiddict/openiddict-core/tree/4.7.0) library has been upgraded to **v4.7.0**. See [#17334](https://github.com/abpframework/abp/pull/17334) for more info. +* ABP v7.4 introduces the `Volo.Abp.Maui.Client` package, which is used by the MAUI mobile application in ABP Commercial. See [#17201](https://github.com/abpframework/abp/pull/17201) for more info. +* In this version, the `AbpAspNetCoreIntegratedTestBase` class gets a generic type parameter, which expects either a startup class or an ABP module class. This allows us to use configurations from an ABP module or old-style ASP.NET Core Startup class in a test application class and this simplifies the test application project. See [#17039](https://github.com/abpframework/abp/pull/17039) for more info. + +## What's New with ABP Commercial 7.4? + +We've also worked on [ABP Commercial](https://commercial.abp.io/) to align the features and changes made in the ABP Framework. The following sections introduce new features coming with ABP Commercial 7.4. + +### Dynamic Text Template Store + +Prior to this version, it was hard to create text templates in different microservices and centrally manage them in a single admin application. For example, if you would define a text template in your ordering microservice, then those text templates could not be seen on the administration microservice because the administration microservice would not have any knowledge about that text template (because it's hard-coded in the ordering microservice). + +For this reason, in this version, the Dynamic Text Template Store has been introduced to make the [Text Template Management module](https://docs.abp.io/en/commercial/latest/modules/text-template-management) compatible with microservices and distributed systems. It allows you to store and get all text templates from a single point. Thanks to that, you can centrally manage the text templates in your admin application. + +> *Note*: If you are upgrading from an earlier version and are using the Text Template Management module, you need to create a new migration and apply it to your database. + +To enable the dynamic template store, you just need to configure the `TextTemplateManagementOptions` and set the `IsDynamicTemplateStoreEnabled` as true in your module class: + +```csharp +Configure(options => +{ + options.IsDynamicTemplateStoreEnabled = true; +}); +``` + +Notice this is only needed in the microservice where you centrally manage your text template contents. So, typically you would use the configuration above in your administration microservice. Other microservices automatically save their text template contents to the central database. + +### Suite: Custom Code Support + +In this version, we have implemented the custom code support in Suite. This allows you to customize the generated code-blocks and preserve your custom code changes in the next CRUD Page Generation in Suite. ABP Suite specifies hook-points to allow adding custom code blocks. Then, the code that you wrote to these hook points will be respected and will not be overridden in the next entity generation. + +![](suite-custom-code.png) + +To enable custom code support, you should check the *Customizable code* option in the crud page generation page. When you enable the custom code support, you will be seeing some hook-points in your application. + +For example, on the C# side, you'll be seeing some abstract classes and classes that derive from them (for entities, application services, interfaces, domain services, and so on...). You can write your custom code in those classes (`*.Extended.cs`) and the next time when you need to re-generate the entity, your custom code will not be overridden (only the base abstract classes will be re-generated and your changes on Suite will be respected): + +Folder structure | Book.Extended.cs +:-------------------------:|:-------------------------: +![](suite-custom-code-backend.png) | ![](book-extended-cs.png) + +> *Note*: If you want to override the entity and add custom code, please do not touch the code between `...` placeholders, because the constructor of the entity should be always re-generated in case of a new property added. + +On the UI side, you can see the *comment placeholders* on the pages for MVC & Blazor applications. These are hook-points provided by ABP Suite and you can write your custom code between these comment sections: + +Folder structure | Books/Index.cshtml +:-------------------------:|:-------------------------: +![](suite-custom-code-ui.png) | ![](book-extended-cshtml.png) + +### MAUI & React Native UI Revisions + +In this version, we have revised MAUI & React Native mobile applications and added new pages, functionalities and made improvements on the UI side. + +![](maui.png) + +For example, in the MAUI application, we have implemented the following functionalities and changed the UI completely: + +* **User Management Page**: Management page for your application users. You can search, add, update, or delete users of your application. +* **Tenants**: Management page for your tenants. +* **Settings**: Management page for your application settings. On this page, you can change **the current language**, **the profile picture**, **the current password**, or/and **the current theme**. + +Also, we have aligned the features on both of these mobile options (MAUI & React Native) and showed them in the ["ABP Community Talks 2023.5: Exploring the Options for Mobile Development with the ABP Framework"](https://community.abp.io/events/mobile-development-with-the-abp-framework-ogtwaz5l). + +> If you have missed the event, you can watch from 👉 [here](https://www.youtube.com/watch?v=-wrdngeKgZw). + +### New LeptonX Theme Features + +In the new version of LeptonX Theme, which is v2.4.0-rc.1, there are some new features that we want to mention. + +#### Mobile Toolbars + +The [Toolbar System](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Toolbars) is used to define *toolbars* on the user interface. Modules (or your application) can add items to a toolbar, then the UI themes can render the toolbar on the layout. + +LeptonX Theme extends this system even further and introduces mobile toolbars with this version. You can create a component and add it as a mobile toolbar as below: + +```csharp +public class MyToolbarContributor : IToolbarContributor +{ + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name == LeptonXToolbars.MainMobile) + { + context.Toolbar.Items.Add(new ToolbarItem(typeof(ShoppingCardToolbarComponent))); + + //other mobile toolbars... + } + + return Task.CompletedTask; + } +} +``` + +Then, the LeptonX Theme will render these mobile toolbars like in the figure below: + +![](mobile-toolbars.png) + +> **Note**: The Angular UI hasn't been completed yet. We aim to complete it as soon as possible and include it in the next release. + +#### New Error Page Designs + +In this version, we have implemented new error pages. Encounter a fresh look during error situations with the 'New Error Page Designs,' providing informative and visually appealing error displays that enhance user experience: + +![](error-page.png) + +#### Fluid Layout + +In this version, LeptonX Theme introduces the fresh-looking **Fluid Layout**, which is a layout that lets you align elements so that they automatically adjust their alignment and proportions for different page sizes and orientations. + +![](fluid-layout.png) + +> You can visit [the live demo of LeptonX Theme](https://x.leptontheme.com/side-menu) and try the Fluid Layout now! + +### Check & Move Related Entities on Deletion/Demand + +In application modules, there are some entities that have complete relationships with each other such as role-user relations. In such cases, it's a typical requirement to check & move related entities that have a relation with the other entity that is about to be deleted. + +For example, if you need to delete an edition from your system, you would typically want to move the tenant that is associated with that edition. For this purpose, in this version, ABP Commercial allows you to move related entities on deletion/demand. + +![](editions.png) + +Currently, this feature is implemented for SaaS and Identity Pro modules and for the following relations: + +* Edition - Tenant +* Role - User +* Organization Unit - User + +Also, it's possible to move the related associated-records before deleting the record. For example, you can move all tenants from an edition as shown in the figure below: + +"Move all tenants" action | "Move all tenants" modal +:-------------------------:|:-------------------------: +![](move-all-tenants.png) | ![](move-tenants.png) + +### CMS Kit Pro: Page Feedback + +In this version, the **Page Feedback** feature has been added to the [CMS Kit Pro](https://docs.abp.io/en/commercial/latest/modules/cms-kit/index) module. This feature allows you to get feedback from a page in your application. + +This is especially useful if you have content that needs feedback from users. For example, if you have documentation or a blog website, it's a common requirement to assess the quality of the articles and get feedback from users. In that case, you can use this feature: + +![](page-feedback.png) + +### Chat Module: Deleting Messages & Conversations + +In this version, the [Chat Module](https://docs.abp.io/en/commercial/latest/modules/chat) allows you to delete individual messages or a complete conversation. + +You can enable or disable the message/conversation deletion globally on your application: + +![](settings.png) + +> **Note**: The Angular UI hasn't been completed yet. We aim to complete it as soon as possible and include it in the next release. + +### Password Complexity Indicators + +In this version, ABP Framework introduces an innovative ["Password Complexity Indicator"](https://docs.abp.io/en/commercial/7.4/ui/angular/password-complexity-indicator-component) feature, designed to enhance security and user experience. This feature dynamically evaluates and rates the strength of user-generated passwords, providing real-time feedback to users as they create or update their passwords. By visually indicating the complexity level, users are guided toward crafting stronger passwords that meet modern security standards. + +![](password-complexity.png) + +You can check the [Password Complexity Indicator Angular documentation](https://docs.abp.io/en/commercial/7.4/ui/angular/password-complexity-indicator-component) to learn more. + +> **Note**: Currently, this feature is only available for the Angular UI, but we will be implemented for other UIs in the next version. + +## Community News + +### DevNot Developer Summit 2023 + +![](developersummit.jpg) + +We are thrilled to announce that the co-founder of [Volosoft](https://volosoft.com/) and Lead Developer of the ABP Framework, Halil Ibrahim Kalkan will give a speech about "Building a Kubernetes Integrated Local Development Environment" in the [Developer Summit 2023 event](https://summit.devnot.com/) on the 7th of October. + +### New ABP Community Posts + +There are exciting articles contributed by the ABP community as always. I will highlight some of them here: + +* [ABP Commercial - GDPR Module Overview](https://community.abp.io/posts/abp-commercial-gdpr-module-overview-kvmsm3ku) by [Engincan Veske](https://twitter.com/EngincanVeske) +* [Video: ABP Framework Data Transfer Objects](https://community.abp.io/videos/abp-framework-data-transfer-objects-qwebfqz5) by [Hamza Albreem](https://github.com/braim23) +* [Video: ABP Framework Essentials: MongoDB](https://community.abp.io/videos/abp-framework-essentials-mongodb-gwlblh5x) by [Hamza Albreem](https://github.com/braim23) +* [ABP Modules and Entity Dependencies](https://community.abp.io/posts/abp-modules-and-entity-dependencies-hn7wr093) by [Jack Fistelmann](https://github.com/nebula2) +* [How to add dark mode support to the Basic Theme in 3 steps?](https://community.abp.io/posts/how-to-add-dark-mode-support-to-the-basic-theme-in-3-steps-ge9c0f85) by [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) +* [Deploying docker image to Azure with yml and bicep through Github Actions](https://community.abp.io/posts/deploying-docker-image-to-azure-with-yml-and-bicep-through-github-actions-cjiuh55m) by [Sturla](https://community.abp.io/members/Sturla) + +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community. + +## Conclusion + +This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://docs.abp.io/en/abp/7.4/Road-Map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v7.4 RC and provide feedback to help us release a more stable version. + +Thanks for being a part of this community! diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cs.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cs.png new file mode 100644 index 0000000000..1179118621 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cs.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cshtml.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cshtml.png new file mode 100644 index 0000000000..0ed90a33de Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/book-extended-cshtml.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/cover-image.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/cover-image.png new file mode 100644 index 0000000000..06ced79397 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/cover-image.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/developersummit.jpg b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/developersummit.jpg new file mode 100644 index 0000000000..65bae90315 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/developersummit.jpg differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/editions.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/editions.png new file mode 100644 index 0000000000..331706daa7 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/editions.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/error-page.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/error-page.png new file mode 100644 index 0000000000..8ece260ec3 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/error-page.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/fluid-layout.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/fluid-layout.png new file mode 100644 index 0000000000..6150f3e2bd Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/fluid-layout.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/maui.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/maui.png new file mode 100644 index 0000000000..4205001d80 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/maui.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/mobile-toolbars.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/mobile-toolbars.png new file mode 100644 index 0000000000..6dcde5da60 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/mobile-toolbars.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-all-tenants.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-all-tenants.png new file mode 100644 index 0000000000..b893360447 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-all-tenants.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-tenants.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-tenants.png new file mode 100644 index 0000000000..fb6b8364fb Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/move-tenants.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/page-feedback.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/page-feedback.png new file mode 100644 index 0000000000..dbdd9fe199 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/page-feedback.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/password-complexity.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/password-complexity.png new file mode 100644 index 0000000000..55bc8a8f43 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/password-complexity.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/settings.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/settings.png new file mode 100644 index 0000000000..1e835661a0 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/settings.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-backend.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-backend.png new file mode 100644 index 0000000000..cb14dfc0f1 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-backend.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-ui.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-ui.png new file mode 100644 index 0000000000..132988a873 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code-ui.png differ diff --git a/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code.png b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code.png new file mode 100644 index 0000000000..2e510d0768 Binary files /dev/null and b/docs/en/Blog-Posts/2023-08-15 v7_4_Preview/suite-custom-code.png differ diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md index 6abf984298..ae688d6981 100644 --- a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md +++ b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md @@ -594,7 +594,7 @@ namespace BookStore.EntityFrameworkCore /* Configure your own tables/entities inside here */ builder.Entity(b => { - b.ToTable(BookStoreConsts.DbTablePrefix + "Authors" + BookStoreConsts.DbSchema); + b.ToTable(BookStoreConsts.DbTablePrefix + "Authors", BookStoreConsts.DbSchema); b.ConfigureByConvention(); b.Property(x => x.Name) @@ -608,7 +608,7 @@ namespace BookStore.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BookStoreConsts.DbTablePrefix + "Books" + BookStoreConsts.DbSchema); + b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema); b.ConfigureByConvention(); b.Property(x => x.Name) @@ -624,7 +624,7 @@ namespace BookStore.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BookStoreConsts.DbTablePrefix + "Categories" + BookStoreConsts.DbSchema); + b.ToTable(BookStoreConsts.DbTablePrefix + "Categories", BookStoreConsts.DbSchema); b.ConfigureByConvention(); b.Property(x => x.Name) @@ -634,7 +634,7 @@ namespace BookStore.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BookStoreConsts.DbTablePrefix + "BookCategories" + BookStoreConsts.DbSchema); + b.ToTable(BookStoreConsts.DbTablePrefix + "BookCategories", BookStoreConsts.DbSchema); b.ConfigureByConvention(); //define composite key diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/README.md b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/README.md new file mode 100644 index 0000000000..2db041436c --- /dev/null +++ b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/README.md @@ -0,0 +1,450 @@ +# Cascading Option Loading with Extensions System in ABP Angular + +This article will show how to load cascading options with an extensions system in ABP Angular. For this example, we'll simulate renting a book process. Besides our default form properties, we'll contribute `Name` property to our `Rent Form Modal` in the Books module. This property will be loaded after `Genre` is selected. + +> Before starting this article, I suggest you read the [ABP Angular Dynamic Form Extensions](https://docs.abp.io/en/abp/latest/UI/Angular/Dynamic-Form-Extensions) + +### Environment + +- **ABP Framework Version:** ~7.3.0 (`~` means that use the latest patch version of the specified release) +- **DB Provider:** MongoDB +- **Angular Version:** ~16.0.0 + +### Project structure + +The books module is not a library; for this demo, it'll placed in the application itself. + +![Folder structure](./assets/img/folder-structure.png) + +- **books folder:** Contains default form properties, tokens, models, etc. It's similar to the ABP module structure. +- Also I've used **standalone** and **signals** feature in this demo. +- **books-extended folder:** Contains only `Name` property for the contribute `Rent Form Modal` inside the Books module. +- **For more readability, I've used TS path aliases in this demo. Don't forget to export files in `index.ts` file 🙂** + +![tsconfig.json file](./assets/img/ts-config-file.png) + +### First look at the demo + +![Cascading Loading Demo](assets/gif/cascading-loading-demo.gif) + +### What is the Extension system? + +![Extensions System Document](./assets/img/extensions-system-document.png) + +# Reviewing the code step by step + +**1. Create default form properties for `Rent Form` in the `Books` module** + +- `getInjected` function is the key point of the cascading loading +- We can reach and track any value from `Service` or `Component` +- In that way we can load options according to the selected value + +```ts +// ~/books/defaults/default-books-form.props.ts + +import { Validators } from "@angular/forms"; +import { map, of } from "rxjs"; +import { ePropType, FormProp } from "@abp/ng.theme.shared/extensions"; +import { BookDto, AuthorService, BooksService } from "../proxy"; +import { RentBookComponent } from "../components"; +import { DefaultOption } from "../utils"; + +const { required } = Validators; + +export const DEFAULT_RENT_FORM_PROPS = FormProp.createMany([ + { + type: ePropType.String, + id: "authorId", + name: "authorId", + displayName: "BookStore::Author", + defaultValue: null, + validators: () => [required], + options: (data) => { + const { authors } = data.getInjected(AuthorService); + + return of([ + DefaultOption, + ...authors().map((author) => ({ value: author.id, key: author.name })), + ]); + }, + }, + { + type: ePropType.String, + id: "genreId", + name: "genreId", + displayName: "BookStore::Genre", + defaultValue: null, + validators: () => [required], + options: (data) => { + const rentBookComponent = data.getInjected(RentBookComponent); + const { genres } = data.getInjected(BooksService); + + const genreOptions = genres().map(({ id, name }) => ({ + value: id, + key: name, + })); + + return rentBookComponent.form.controls.authorId.valueChanges.pipe( + map((value: string | undefined) => + value ? [DefaultOption, ...genreOptions] : [DefaultOption] + ) + ); + }, + }, + { + type: ePropType.Date, + id: "returnDate", + name: "returnDate", + displayName: "BookStore::ReturnDate", + defaultValue: null, + validators: () => [required], + }, +]); +``` + +**2. Configure tokens and config options** + +The documentation explains these steps; that's why I won't explain it again. If documents or samples are not enough, please let me know in the comments 🙂 + +**Extensions Token** + +```ts +// ~/books/tokens/extensions.token.ts + +import { CreateFormPropContributorCallback } from "@abp/ng.theme.shared/extensions"; +import { InjectionToken } from "@angular/core"; +import { BookDto } from "../proxy"; +import { eBooksComponents } from "../enums"; +import { DEFAULT_RENT_FORM_PROPS } from "../defaults"; + +export const DEFAULT_BOOK_STORE_CREATE_FORM_PROPS = { + [eBooksComponents.RentBook]: DEFAULT_RENT_FORM_PROPS, +}; + +export const BOOK_STORE_RENT_FORM_PROP_CONTRIBUTORS = + new InjectionToken( + "BOOK_STORE_RENT_FORM_PROP_CONTRIBUTORS" + ); + +type CreateFormPropContributors = Partial<{ + [eBooksComponents.RentBook]: CreateFormPropContributorCallback[]; + /** + * Other creation form prop contributors... + */ + // [eBooksComponents.CreateBook]: CreateFormPropContributorCallback[]; +}>; +``` + +**Extensions Config Option** + +```ts +// ~/books/models/config-options.ts + +import { CreateFormPropContributorCallback } from "@abp/ng.theme.shared/extensions"; +import { BookDto } from "../proxy"; +import { eBooksComponents } from "../enums"; + +export type BookStoreRentFormPropContributors = Partial<{ + [eBooksComponents.RentBook]: CreateFormPropContributorCallback[]; +}>; + +export interface BooksConfigOptions { + rentFormPropContributors?: BookStoreRentFormPropContributors; +} +``` + +**3. Extensions Guard** + +It'll to collect all contributors from [ExtensionsService](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/theme-shared/extensions/src/lib/services/extensions.service.ts) + +```ts +// ~/books/guards/extensions.guard.ts + +import { Injectable, inject } from "@angular/core"; +import { Observable, map, tap } from "rxjs"; +import { ConfigStateService, IAbpGuard } from "@abp/ng.core"; +import { + ExtensionsService, + getObjectExtensionEntitiesFromStore, + mapEntitiesToContributors, + mergeWithDefaultProps, +} from "@abp/ng.theme.shared/extensions"; +import { + BOOK_STORE_RENT_FORM_PROP_CONTRIBUTORS, + DEFAULT_BOOK_STORE_CREATE_FORM_PROPS, +} from "../tokens"; + +@Injectable() +export class BooksExtensionsGuard implements IAbpGuard { + protected readonly configState = inject(ConfigStateService); + protected readonly extensions = inject(ExtensionsService); + + canActivate(): Observable { + const createFormContributors = + inject(BOOK_STORE_RENT_FORM_PROP_CONTRIBUTORS, { optional: true }) || {}; + + return getObjectExtensionEntitiesFromStore( + this.configState, + "BookStore" + ).pipe( + mapEntitiesToContributors(this.configState, "BookStore"), + tap((objectExtensionContributors) => { + mergeWithDefaultProps( + this.extensions.createFormProps, + DEFAULT_BOOK_STORE_CREATE_FORM_PROPS, + objectExtensionContributors.createForm, + createFormContributors + ); + }), + map(() => true) + ); + } +} +``` + +Yes, I'm still using class-based guard 🙂 much more flexible... + +**4. RentBookComponent** + +- Our trackable variable is defined here `(form:FormGroup)`, which means We'll track this variable in `options` property at defaults || contributors files. +- Providing `AuthorService`, also `EXTENSIONS_IDENTIFIER` for the reach dynamic properties + +```ts +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Injector, + Output, + inject, +} from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { CoreModule, uuid } from "@abp/ng.core"; +import { ThemeSharedModule } from "@abp/ng.theme.shared"; +import { + EXTENSIONS_IDENTIFIER, + FormPropData, + UiExtensionsModule, + generateFormFromProps, +} from "@abp/ng.theme.shared/extensions"; +import { AuthorService, BookDto, BooksService } from "../../proxy"; +import { eBooksComponents } from "../../enums"; + +@Component({ + standalone: true, + selector: "app-rent-book", + templateUrl: "./rent-book.component.html", + imports: [CoreModule, UiExtensionsModule, ThemeSharedModule], + providers: [ + { + provide: EXTENSIONS_IDENTIFIER, + useValue: eBooksComponents.RentBook, + }, + AuthorService, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class RentBookComponent { + protected readonly injector = inject(Injector); + protected readonly authorService = inject(AuthorService); + protected readonly booksService = inject(BooksService); + + //#region Just for demo + readonly #authors = this.authorService.authors(); + readonly #genres = this.booksService.genres(); + readonly #books = this.booksService.books(); + //#endregion + + protected modalVisible = true; + @Output() modalVisibleChange = new EventEmitter(); + + selected: BookDto; + form: FormGroup; + modalBusy = false; + + protected buildForm(): void { + const data = new FormPropData(this.injector, this.selected); + this.form = generateFormFromProps(data); + } + + constructor() { + this.buildForm(); + } + + save(): void { + if (this.form.invalid) { + return; + } + + this.modalBusy = true; + + const { authorId, genreId, bookId, returnDate } = this.form.value; + + //#region Just for demo + const authorName = this.#authors.find(({ id }) => id === authorId).name; + const genreName = this.#genres.find(({ id }) => id === genreId).name; + const bookName = this.#books.find(({ id }) => id === bookId).name; + //#endregion + + this.booksService.rentedBooks.update((books) => [ + { + id: uuid(), + name: bookName, + author: authorName, + genre: genreName, + returnDate, + }, + ...books, + ]); + + this.modalBusy = false; + this.modalVisible = false; + } +} +``` + +```html + + +

{{ 'BookStore::RentABook' | abpLocalization }}

+
+ + + +
+ +
+
+ +
+ +
+
+ + + + + {{ 'AbpIdentity::Save' | abpLocalization }} + + +
+``` + +Up to now, we have constructed our module's default form properties. + +- As you can see, there are no book names we'll add them via contributors + +![Rent Form Without Contribution](./assets/img/rent-form-without-contribution.png) + +## Next, add new property dynamically (book name list as dropdown) + +- Created new folder ./src/app/books-extended +- Create contributors/form-prop.contributors.ts + +```ts +// ~/books-extened/contributors/form-prop.contributors.ts + +import { Validators } from "@angular/forms"; +import { map } from "rxjs"; +import { + ePropType, + FormProp, + FormPropList, +} from "@abp/ng.theme.shared/extensions"; +import { + BookDto, + BookStoreRentFormPropContributors, + BooksService, + DefaultOption, + RentBookComponent, + eBooksComponents, +} from "@book-store/books"; + +const { required, maxLength } = Validators; + +const bookIdProp = new FormProp({ + type: ePropType.String, + id: "bookId", + name: "bookId", + displayName: "BookStore::Name", + options: (data) => { + const rentBook = data.getInjected(RentBookComponent); + const { books } = data.getInjected(BooksService); + const bookOptions = books().map(({ id, name }) => ({ + value: id, + key: name, + })); + + return rentBook.form.controls.genreId.valueChanges.pipe( + map((value: string | undefined) => + value ? [DefaultOption, ...bookOptions] : [DefaultOption] + ) + ); + }, + validators: () => [required, maxLength(255)], +}); + +export function bookIdPropContributor(propList: FormPropList) { + propList.addByIndex(bookIdProp, 2); +} + +export const bookStoreRentFormPropContributors: BookStoreRentFormPropContributors = + { + [eBooksComponents.RentBook]: [bookIdPropContributor], + }; +``` + +- Load new contributions via routing & forLazy method + +```ts +// ~/app-routing.module.ts +import { bookStoreRentFormPropContributors } from "./books-extended/contributors/form-prop.contributors"; + +const routes: Routes = [ + // other routes... + { + path: "books", + loadChildren: () => + import("@book-store/books").then((m) => + m.BooksModule.forLazy({ + rentFormPropContributors: bookStoreRentFormPropContributors, + }) + ), + }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, {})], + exports: [RouterModule], +}) +export class AppRoutingModule {} +``` + +Finally, we've added a new property to our module, and it'll be loaded after `Genre` is selected. + +## Conclusion + +![Cascading Loading Demo](assets/gif/cascading-loading-demo.gif) + +- In ABP Angular, we can create form properties and load dropdown options dynamically via the Extensions System +- We can reach and track any value from `Service` or `Component` +- We can create our custom library or module and contribute it to any module in the application + +Thanks for reading, I hope it was helpful. If you have any questions, please let me know in the comments section. 👋👋 + +> You can find the source code of this article on [Github](https://github.com/abpframework/abp-samples/tree/master/AngularCascadingOptionLoading/Volo.BookStore) diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/gif/cascading-loading-demo.gif b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/gif/cascading-loading-demo.gif new file mode 100644 index 0000000000..ae69070f28 Binary files /dev/null and b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/gif/cascading-loading-demo.gif differ diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/extensions-system-document.png b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/extensions-system-document.png new file mode 100644 index 0000000000..7f806ec42d Binary files /dev/null and b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/extensions-system-document.png differ diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/folder-structure.png b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/folder-structure.png new file mode 100644 index 0000000000..2d3a828773 Binary files /dev/null and b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/folder-structure.png differ diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/rent-form-without-contribution.png b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/rent-form-without-contribution.png new file mode 100644 index 0000000000..e29d525f7b Binary files /dev/null and b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/rent-form-without-contribution.png differ diff --git a/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/ts-config-file.png b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/ts-config-file.png new file mode 100644 index 0000000000..6b06e8ca90 Binary files /dev/null and b/docs/en/Community-Articles/2023-07-09-Cascading-Option-Loading-With-Extensions/assets/img/ts-config-file.png differ diff --git a/docs/en/Emailing.md b/docs/en/Emailing.md index bfb3058862..48635b2565 100644 --- a/docs/en/Emailing.md +++ b/docs/en/Emailing.md @@ -58,7 +58,11 @@ namespace MyProject `SendAsync` method has overloads to supply more parameters like; * **from**: You can set this as the first argument to set a sender email address. If not provided, the default sender address is used (see the email settings below). +* **to**: You can set the target email address. +* **subject**: You can set the email subject. +* **body**: You can set the email body. * **isBodyHtml**: Indicates whether the email body may contain HTML tags. **Default: true**. +* **additionalEmailSendingArgs**: This parameter is used to pass additional arguments to the `IEmailSender` implementation. Include: CC(Carbon copy), a list of `EmailAttachment` and an extra properties. > `IEmailSender` is the suggested way to send emails, since it makes your code provider independent. diff --git a/docs/en/Entity-Framework-Core-Migrations.md b/docs/en/Entity-Framework-Core-Migrations.md index 716038d412..9ac7e76f24 100644 --- a/docs/en/Entity-Framework-Core-Migrations.md +++ b/docs/en/Entity-Framework-Core-Migrations.md @@ -173,7 +173,7 @@ First step is to change the connection string section inside all the `appsetting ````json "ConnectionStrings": { - "Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" } ```` @@ -184,7 +184,7 @@ Change it as shown below: "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True", "AbpPermissionManagement": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True", "AbpSettingManagement": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True", - "AbpAuditLogging": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True" + "AbpAuditLogging": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore_SecondDb;Trusted_Connection=True" } ```` diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index e2cfd21a05..cb9393b1aa 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -594,6 +594,18 @@ Whenever you access to a property/collection, EF Core automatically performs an See also [lazy loading document](https://docs.microsoft.com/en-us/ef/core/querying/related-data/lazy) of the EF Core. +## Read-Only Repositories + +ABP Framework provides read-only [repository](Repositories.md) interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`) to explicitly indicate that your purpose is to query data, but not change it. If so, you can inject these interfaces into your services. + +Entity Framework Core read-only repository implementation uses [EF Core's No-Tracking feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries). That means the entities returned from the repository will not be tracked by the EF Core [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/), because it is expected that you won't update entities queried from a read-only repository. If you need to track the entities, you can still use the [AsTracking()](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.astracking) extension method on the LINQ expression, or `EnableTracking()` extension method on the repository object (See *Enabling / Disabling the Change Tracking* section in this document). + +> This behavior works only if the repository object is injected with one of the read-only repository interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`). It won't work if you have injected a standard repository (e.g. `IRepository<...>`) then casted it to a read-only repository interface. + +## Enabling / Disabling the Change Tracking + +In addition to the read-only repositories, ABP allows to manually control the change tracking behavior for querying objects. Please see the *Enabling / Disabling the Change Tracking* section of the [Repositories documentation](Repositories.md) to learn how to use it. + ## Access to the EF Core API In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository pattern). However, if you want to access the `DbContext` instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example: diff --git a/docs/en/Getting-Started-Running-Solution-Single-Layer.md b/docs/en/Getting-Started-Running-Solution-Single-Layer.md index cef80c7807..f18f3119f9 100644 --- a/docs/en/Getting-Started-Running-Solution-Single-Layer.md +++ b/docs/en/Getting-Started-Running-Solution-Single-Layer.md @@ -20,7 +20,7 @@ Check the **connection string** in the `appsettings.json` file under the `YourPr ````json "ConnectionStrings": { - "Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" } ```` diff --git a/docs/en/Getting-Started-Running-Solution.md b/docs/en/Getting-Started-Running-Solution.md index 36cd5ffe0a..f3adcac67d 100644 --- a/docs/en/Getting-Started-Running-Solution.md +++ b/docs/en/Getting-Started-Running-Solution.md @@ -21,7 +21,7 @@ Check the **connection string** in the `appsettings.json` file under the {{if Ti ````json "ConnectionStrings": { - "Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" } ```` diff --git a/docs/en/Object-To-Object-Mapping.md b/docs/en/Object-To-Object-Mapping.md index c12b260921..40efdd7ee6 100644 --- a/docs/en/Object-To-Object-Mapping.md +++ b/docs/en/Object-To-Object-Mapping.md @@ -320,9 +320,22 @@ public class MyCustomUserMapper : IObjectMapper, ITransientDepend } ```` -ABP automatically discovers and registers the `MyCustomUserMapper` and it is automatically used whenever you use the `IObjectMapper` to map `User` to `UserDto`. - -A single class may implement more than one `IObjectMapper` each for a different object pairs. +ABP automatically discovers and registers the `MyCustomUserMapper` and it is automatically used whenever you use the `IObjectMapper` to map `User` to `UserDto`. A single class may implement more than one `IObjectMapper` each for a different object pairs. > This approach is powerful since `MyCustomUserMapper` can inject any other service and use in the `Map` methods. +Once you implement `IObjectMapper`, ABP can automatically convert a collection of `User` objects to a collection of `UserDto` objects. The following generic collection types are supported: + +* `IEnumerable` +* `ICollection` +* `Collection` +* `IList` +* `List` +* `T[]` (array) + +**Example:** + +````csharp +var users = await _userRepository.GetListAsync(); // returns List +var dtos = ObjectMapper.Map, List>(users); // creates List +```` diff --git a/docs/en/Repositories.md b/docs/en/Repositories.md index 95f908d004..03fb27ab50 100644 --- a/docs/en/Repositories.md +++ b/docs/en/Repositories.md @@ -176,6 +176,77 @@ Some features (like soft-delete, multi-tenancy and audit logging) won't work, so The `EnsureExistsAsync` extension method accepts entity id or entities query expression to ensure entities exist, otherwise, it will throw `EntityNotFoundException`. +### Enabling / Disabling the Change Tracking + +ABP provides repository extension methods and attributes those can be used to control the change tracking behavior for queried entities in the underlying database provider. + +Disabling change tracking can gain performance if you query many entities from the database for read-only purposes. Querying single or a few entities won't make much performance difference, but you are free to use it whenever you like. + +> If the underlying database provider doesn't support change tracking, then this system won't have any effect. [Entity Framework Core](Entity-Framework-Core.md) supports change tracking, for example, while the [MongoDB](MongoDB.md) provider doesn't support it. + +#### Repository Extension Methods for Change Tracking + +Change tracking is enabled unless you explicitly disable it. + +**Example: Using the `DisableTracking` extension method** + +````csharp +public class MyDemoService : ApplicationService +{ + private readonly IRepository _personRepository; + + public MyDemoService(IRepository personRepository) + { + _personRepository = personRepository; + } + + public async Task DoItAsync() + { + // Change tracking is enabled in that point (by default) + + using (_personRepository.DisableTracking()) + { + // Change tracking is disabled in that point + var list = await _personRepository.GetPagedListAsync(0, 100, "Name ASC"); + } + + // Change tracking is enabled in that point (by default) + } +} +```` + +> `DisableTracking` extension method returns a `IDisposable` object, so you can safely **restore** the change tracking behavior to the **previous state** one the `using` block ends. Basically, `DisableTracking` method ensures that the change tracking is disabled inside the `using` block, but doesn't affect outside of the `using` block. That means, if change tracking was already disabled, `DisableTracking` and the disposable return value do nothing. + +`EnableTracking()` method works exactly opposite to the `DisableTracking()` method. You typically won't use it (because the change tracking is already enabled by default), but it is there in case of you need that. + +#### Attributes for Change Tracking + +You typically use the `DisableTracking()` method for the application service methods those only returns data, but doesn't make any change on entities. For such cases, you can use the `DisableEntityChangeTracking` attribute on your method/class as a shortcut to disable the change tracking for whole method body. + +**Example: Using the `DisableEntityChangeTracking` attribute on a method** + +````csharp +[DisableEntityChangeTracking] +public virtual async Task> GetListAsync() +{ + /* We disabled the change tracking in this method + because we won't change the people objects */ + var people = await _personRepository.GetListAsync(); + return ObjectMapper.Map, List(people); +} +```` + +`EnableEntityChangeTracking` can be used for the opposite purpose, and it ensures that the change tracking is enabled for a given method. Since the change tracking is enabled by default, `EnableEntityChangeTracking` may be needed only if you know that your method is called from a context that disables the change tracking. + +`DisableEntityChangeTracking` and `EnableEntityChangeTracking` attributes can be used on a **method** or on a **class** (which affects all of the class methods). + +ABP uses dynamic proxying to make these attributes working. There are some rules here: + +* If you are **not injecting** the service over an interface (like `IPersonAppService`), then the methods of the service must be `virtual`. Otherwise, [dynamic proxy / interception](Dynamic-Proxying-Interceptors.md) system can not work. +* Only `async` methods (methods returning a `Task` or `Task`) are intercepted. + +> Change tracking behavior doesn't affect tracking entity objects returned from `InsertAsync` and `UpdateAsync` methods. The objects returned from these methods are always tracked (if the underlying provider has the change tracking feature) and any change you made to these objects are saved into the database. + ## Other Generic Repository Types Standard `IRepository` interface exposes the standard `IQueryable` and you can freely query using the standard LINQ methods. This is fine for most of the applications. However, some ORM providers or database systems may not support standard `IQueryable` interface. If you want to use such providers, you can't rely on the `IQueryable`. @@ -205,8 +276,6 @@ Methods: - `WithDetails()` 1 overload - `WithDetailsAsync()` 1 overload - - Where as the `IReadOnlyBasicRepository` provides the following methods: - `GetCountAsync()` @@ -217,6 +286,12 @@ They can all be seen as below: ![generic-repositories](images/generic-repositories.png) +#### Read Only Repositories behavior in Entity Framework Core + +Entity Framework Core read-only repository implementation uses [EF Core's No-Tracking feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries). That means the entities returned from the repository will not be tracked by the EF Core [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/), because it is expected that you won't update entities queried from a read-only repository. If you need to track the entities, you can still use the [AsTracking()](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.astracking) extension method on the LINQ expression, or `EnableTracking()` extension method on the repository object (See *Enabling / Disabling the Change Tracking* section in this document). + +> This behavior works only if the repository object is injected with one of the read-only repository interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`). It won't work if you have injected a standard repository (e.g. `IRepository<...>`) then casted it to a read-only repository interface. + ### Generic Repository without a Primary Key If your entity does not have an Id primary key (it may have a composite primary key for instance) then you cannot use the `IRepository` (or basic/readonly versions) defined above. In that case, you can inject and use `IRepository` for your entity. diff --git a/docs/en/UI/AspNetCore/Testing.md b/docs/en/UI/AspNetCore/Testing.md index 2c880594d3..6efc967cb0 100644 --- a/docs/en/UI/AspNetCore/Testing.md +++ b/docs/en/UI/AspNetCore/Testing.md @@ -198,23 +198,10 @@ ABP Framework doesn't provide any infrastructure to test your JavaScript code. Y > Volo.Abp.AspNetCore.TestBase package is already installed in the `.Web.Tests` project. -This package provides the `AbpAspNetCoreIntegratedTestBase` as the fundamental base class to derive the test classes from. The `MyProjectWebTestBase` base class used above inherits from the `AbpAspNetCoreIntegratedTestBase`, so we indirectly inherited the `AbpAspNetCoreIntegratedTestBase`. +This package provides the `AbpWebApplicationFactoryIntegratedTest` as the fundamental base class to derive the test classes from. It's inherited from the [WebApplicationFactory](https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests) class provided by the ASP.NET Core. -### Base Properties - -The `AbpAspNetCoreIntegratedTestBase` provides the following base properties those are used in the tests: - -* `Server`: A `TestServer` instance that hosts the web application in tests. -* `Client`: An `HttpClient` instance that is configured to perform requests to the test server. -* `ServiceProvider`: The service provider that you can resolve services in case of need. - -### Base Methods - -`AbpAspNetCoreIntegratedTestBase` provides the following methods that you can override if you need to customize the test server: - -* `ConfigureServices` can be overridden to register/replace services only for the derived test class. -* `CreateHostBuilder` can be used to customize building the `IHostBuilder`. +The `MyProjectWebTestBase` base class used above inherits from the `AbpWebApplicationFactoryIntegratedTest`, so we indirectly inherited the `AbpWebApplicationFactoryIntegratedTest`. See Also - +* [Integration tests in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests) * [Overall / Server Side Testing](../../Testing.md) \ No newline at end of file diff --git a/docs/zh-Hans/Getting-Started-Running-Solution.md b/docs/zh-Hans/Getting-Started-Running-Solution.md index 8ecd85ec58..f0a4942d64 100644 --- a/docs/zh-Hans/Getting-Started-Running-Solution.md +++ b/docs/zh-Hans/Getting-Started-Running-Solution.md @@ -21,7 +21,7 @@ ````json "ConnectionStrings": { - "Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True" } ```` diff --git a/docs/zh-Hans/UI/AspNetCore/Testing.md b/docs/zh-Hans/UI/AspNetCore/Testing.md index e5b09353fb..1dfdbe367e 100644 --- a/docs/zh-Hans/UI/AspNetCore/Testing.md +++ b/docs/zh-Hans/UI/AspNetCore/Testing.md @@ -198,23 +198,10 @@ ABP框架不提供任何基础设施来测试JavaScript代码. 你可以使用 > Volo.Abp.AspNetCore.TestBase 已经安装在 `.Web.Tests` 项目中. -此包提供的`AbpAspNetCoreIntegratedTestBase`作为派生测试类的基类. 上面使用的`MyProjectWebTestBase`继承自`AbpAspNetCoreIntegratedTestBase`, 因此我们间接继承了`AbpAspNetCoreIntegratedTestBase`. - -### 基本属性 - -`AbpAspNetCoreIntegratedTestBase` 提供了测试中使用的以下基本属性: - -* `Server`: 在测试中托管web应用程序的`TestServer`实例. -* `Client`: 为执行对测试服务器的请求配置`HttpClient`实例. -* `ServiceProvider`: 可以在你需要时处理服务提供服务. - -### 基本方法 - -`AbpAspNetCoreIntegratedTestBase` 提供了以下方法, 如果需要自定义测试服务器, 可以重写这些方法: - -* `ConfigureServices` 仅为派生测试类注册/替换服务时可以重写使用. -* `CreateHostBuilder` 可用于自定义生成 `IHostBuilder`. +此包提供的`AbpWebApplicationFactoryIntegratedTest`作为派生测试类的基类. 它继承自ASP.NET Core提供的[WebApplicationFactory](https://learn.microsoft.com/zh-cn/aspnet/core/test/integration-tests)类。 +上面使用的`MyProjectWebTestBase`继承自`AbpWebApplicationFactoryIntegratedTest`, 因此我们间接继承了`AbpWebApplicationFactoryIntegratedTest`. 另请参阅 +* [ASP.NET Core 中的集成测试](https://learn.microsoft.com/zh-cn/aspnet/core/test/integration-tests) * [总览/服务器端测试](../../Testing.md) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/DaprAspNetCore/AbpDaprEndpointRouteBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/DaprAspNetCore/AbpDaprEndpointRouteBuilderExtensions.cs index b5866c5a68..24f68ef9ab 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/DaprAspNetCore/AbpDaprEndpointRouteBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/DaprAspNetCore/AbpDaprEndpointRouteBuilderExtensions.cs @@ -30,7 +30,7 @@ namespace Dapr /// /// An optional delegate used to configure the subscriptions. /// - public Func, Task> SubscriptionsCallback { get; set; } + public Func, Task>? SubscriptionsCallback { get; set; } } /// @@ -41,32 +41,32 @@ namespace Dapr /// /// Gets or sets the topic name. /// - public string Topic { get; set; } + public string Topic { get; set; } = default!; /// /// Gets or sets the pubsub name /// - public string PubsubName { get; set; } + public string PubsubName { get; set; } = default!; /// /// Gets or sets the route /// - public string Route { get; set; } + public string? Route { get; set; } /// /// Gets or sets the routes /// - public AbpRoutes Routes { get; set; } + public AbpRoutes? Routes { get; set; } /// /// Gets or sets the metadata. /// - public AbpMetadata Metadata { get; set; } + public AbpMetadata? Metadata { get; set; } /// /// Gets or sets the deadletter topic. /// - public string DeadLetterTopic { get; set; } + public string? DeadLetterTopic { get; set; } } /// @@ -99,12 +99,12 @@ namespace Dapr /// /// Gets or sets the default route /// - public string Default { get; set; } + public string? Default { get; set; } /// /// Gets or sets the routing rules /// - public List Rules { get; set; } + public List? Rules { get; set; } } /// @@ -115,12 +115,12 @@ namespace Dapr /// /// Gets or sets the CEL expression to match this route. /// - public string Match { get; set; } + public string Match { get; set; } = default!; /// /// Gets or sets the path of the route. /// - public string Path { get; set; } + public string Path { get; set; } = default!; } } @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Builder return CreateSubscribeEndPoint(endpoints, options); } - private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRouteBuilder endpoints, AbpSubscribeOptions options = null) + private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRouteBuilder endpoints, AbpSubscribeOptions? options = null) { if (endpoints is null) { @@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Builder return endpoints.MapGet("dapr/subscribe", async context => { - var logger = context.RequestServices.GetRequiredService().CreateLogger("DaprTopicSubscription"); + var logger = context.RequestServices.GetService()?.CreateLogger("DaprTopicSubscription"); var dataSource = context.RequestServices.GetRequiredService(); var subscriptions = dataSource.Endpoints .OfType() @@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.Builder var topicMetadata = e.Metadata.GetOrderedMetadata(); var originalTopicMetadata = e.Metadata.GetOrderedMetadata(); - var subs = new List<(string PubsubName, string Name, string DeadLetterTopic, bool? EnableRawPayload, string Match, int Priority, Dictionary OriginalTopicMetadata, string MetadataSeparator, RoutePattern RoutePattern)>(); + var subs = new List<(string PubsubName, string Name, string? DeadLetterTopic, bool? EnableRawPayload, string Match, int Priority, Dictionary OriginalTopicMetadata, string? MetadataSeparator, RoutePattern RoutePattern)>(); for (int i = 0; i < topicMetadata.Count(); i++) { @@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Builder { var first = e.First(); var rawPayload = e.Any(e => e.EnableRawPayload.GetValueOrDefault()); - var metadataSeparator = e.FirstOrDefault(e => !string.IsNullOrEmpty(e.MetadataSeparator)).MetadataSeparator ?? ","; + var metadataSeparator = e.FirstOrDefault(e => !string.IsNullOrEmpty(e.MetadataSeparator)).MetadataSeparator?.ToString() ?? ","; var rules = e.Where(e => !string.IsNullOrEmpty(e.Match)).ToList(); var defaultRoutes = e.Where(e => string.IsNullOrEmpty(e.Match)).Select(e => RoutePatternToString(e.RoutePattern)).ToList(); var defaultRoute = defaultRoutes.FirstOrDefault(); @@ -276,7 +276,7 @@ namespace Microsoft.AspNetCore.Builder .OrderBy(e => (e.PubsubName, e.Topic)) .ToList(); - await options?.SubscriptionsCallback(subscriptions); + await options?.SubscriptionsCallback!(subscriptions)!; await context.Response.WriteAsync(JsonSerializer.Serialize(subscriptions, new JsonSerializerOptions { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj index f31ded0e06..96b196b67f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs index b1d5bac7fb..946c39f59c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs @@ -41,8 +41,8 @@ public class AbpAspNetCoreMvcDaprEventsController : AbpController } else { - var eventData = daprSerializer.Deserialize(data, distributedEventBus.GetEventType(topic)); - await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(topic), eventData); + var eventData = daprSerializer.Deserialize(data, distributedEventBus.GetEventType(topic!)); + await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(topic!), eventData); } return Ok(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj index 03bb453ba2..1839113d06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs index dd0c6a5300..aa7d17072b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs @@ -50,9 +50,9 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep return expectedAppApiToken == headerAppApiToken; } - public virtual string GetDaprAppApiTokenOrNull() + public virtual string? GetDaprAppApiTokenOrNull() { - string apiTokenHeader = HttpContext.Request.Headers["dapr-api-token"]; + string? apiTokenHeader = HttpContext.Request.Headers["dapr-api-token"]; if (string.IsNullOrEmpty(apiTokenHeader) || apiTokenHeader.Length < 1) { return null; @@ -61,7 +61,7 @@ public class DaprAppApiTokenValidator : IDaprAppApiTokenValidator, ISingletonDep return apiTokenHeader; } - protected virtual string GetConfiguredAppApiTokenOrNull() + protected virtual string? GetConfiguredAppApiTokenOrNull() { return HttpContext .RequestServices diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprHttpContextExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprHttpContextExtensions.cs index aa81765b12..e73eaec4f7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprHttpContextExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprHttpContextExtensions.cs @@ -22,7 +22,7 @@ public static class DaprHttpContextExtensions .IsValidDaprAppApiToken(); } - public static string GetDaprAppApiTokenOrNull(HttpContext httpContext) + public static string? GetDaprAppApiTokenOrNull(HttpContext httpContext) { return httpContext .RequestServices diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/IDaprAppApiTokenValidator.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/IDaprAppApiTokenValidator.cs index 66fd833b77..f54f0aa8cf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/IDaprAppApiTokenValidator.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/IDaprAppApiTokenValidator.cs @@ -6,5 +6,5 @@ public interface IDaprAppApiTokenValidator bool IsValidDaprAppApiToken(); - string GetDaprAppApiTokenOrNull(); + string? GetDaprAppApiTokenOrNull(); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 9e3b0bfba2..f1d014b76a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -145,7 +145,7 @@ public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvide ActionApiDescriptionModel.Create( uniqueMethodName, method, - apiDescription.RelativePath, + apiDescription.RelativePath!, apiDescription.HttpMethod, GetSupportedVersions(controllerType, method, setting), allowAnonymous, diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs index 8d5f2d4c4a..1301a5e823 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs @@ -40,11 +40,11 @@ public class AbpModelMetadataProvider : DefaultModelMetadataProvider { foreach (var validationAttribute in detail.ModelAttributes.Attributes.OfType()) { - NormalizeValidationAttrbute(validationAttribute); + NormalizeValidationAttribute(validationAttribute); } } - protected virtual void NormalizeValidationAttrbute(ValidationAttribute validationAttribute) + protected virtual void NormalizeValidationAttribute(ValidationAttribute validationAttribute) { if (validationAttribute.ErrorMessage == null) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs index b912d3905a..d4fd27d889 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs @@ -32,7 +32,7 @@ public class ServiceProxyGenerationModel public ProxyScriptingModel CreateOptions() { - var options = new ProxyScriptingModel(Type, UseCache); + var options = new ProxyScriptingModel(Type!, UseCache); if (!Modules.IsNullOrEmpty()) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs index 505c07a3e1..cd87c55ea4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs @@ -1,14 +1,15 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; using System.Reflection; namespace Volo.Abp.AspNetCore.Mvc.Validation; public static class ValidationAttributeHelper { - private static readonly PropertyInfo ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) + private readonly static PropertyInfo ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) .GetProperty("ErrorMessageString", BindingFlags.Instance | BindingFlags.NonPublic)!; - private static readonly PropertyInfo ValidationAttributeCustomErrorMessageSetProperty = typeof(ValidationAttribute) + private readonly static PropertyInfo ValidationAttributeCustomErrorMessageSetProperty = typeof(ValidationAttribute) .GetProperty("CustomErrorMessageSet", BindingFlags.Instance | BindingFlags.NonPublic)!; public static void SetDefaultErrorMessage(ValidationAttribute validationAttribute) @@ -24,7 +25,14 @@ public static class ValidationAttributeHelper } } - validationAttribute.ErrorMessage = - ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; + try + { + var errorMessageString = ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; + validationAttribute.ErrorMessage = errorMessageString; + } + catch (Exception e) + { + // ignored + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj index a6f6a55f39..5bf1cc54aa 100644 --- a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj @@ -28,6 +28,7 @@ + diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreAsyncIntegratedTestBase.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreAsyncIntegratedTestBase.cs index 8892623364..e6c49d475c 100644 --- a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreAsyncIntegratedTestBase.cs +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreAsyncIntegratedTestBase.cs @@ -13,6 +13,7 @@ using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.TestBase; +[Obsolete("Use AbpWebApplicationFactoryIntegratedTest instead.")] public class AbpAspNetCoreAsyncIntegratedTestBase where TModule : IAbpModule { diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs index c362d5074c..731b21ea03 100644 --- a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs @@ -14,6 +14,7 @@ namespace Volo.Abp.AspNetCore.TestBase; /// /// Can be a module type or old-style ASP.NET Core Startup class. /// +[Obsolete("Use AbpWebApplicationFactoryIntegratedTest instead.")] public abstract class AbpAspNetCoreIntegratedTestBase : AbpTestBaseWithServiceProvider, IDisposable where TStartupModule : class { @@ -51,7 +52,7 @@ public abstract class AbpAspNetCoreIntegratedTestBase : AbpTestB { webBuilder.UseStartup(); } - + webBuilder.UseAbpTestServer(); }) .UseAutofac() diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpWebApplicationFactoryIntegratedTest.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpWebApplicationFactoryIntegratedTest.cs new file mode 100644 index 0000000000..c7b5f48ebe --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpWebApplicationFactoryIntegratedTest.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Volo.Abp.AspNetCore.TestBase; + +public abstract class AbpWebApplicationFactoryIntegratedTest : WebApplicationFactory + where TProgram : class +{ + protected HttpClient Client { get; set; } + + protected IServiceProvider ServiceProvider => Services; + + protected AbpWebApplicationFactoryIntegratedTest() + { + Client = CreateClient(new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = false + }); + ServiceProvider.GetRequiredService().Server = Server; + } + + protected override IHost CreateHost(IHostBuilder builder) + { + builder.ConfigureServices(ConfigureServices); + return base.CreateHost(builder); + } + + protected virtual T? GetService() + { + return Services.GetService(); + } + + protected virtual T GetRequiredService() where T : notnull + { + return Services.GetRequiredService(); + } + + protected virtual void ConfigureServices(IServiceCollection services) + { + + } + + #region GetUrl + + /// + /// Gets default URL for given controller type. + /// + /// The type of the controller. + protected virtual string GetUrl() + { + return "/" + typeof(TController).Name.RemovePostFix("Controller", "AppService", "ApplicationService", "IntService", "IntegrationService", "Service"); + } + + /// + /// Gets default URL for given controller type's given action. + /// + /// The type of the controller. + protected virtual string GetUrl(string actionName) + { + return GetUrl() + "/" + actionName; + } + + /// + /// Gets default URL for given controller type's given action with query string parameters (as anonymous object). + /// + /// The type of the controller. + protected virtual string GetUrl(string actionName, object queryStringParamsAsAnonymousObject) + { + var url = GetUrl(actionName); + + var dictionary = new RouteValueDictionary(queryStringParamsAsAnonymousObject); + if (dictionary.Any()) + { + url += "?" + dictionary.Select(d => $"{d.Key}={d.Value}").JoinAsString("&"); + } + + return url; + } + + #endregion +} diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..403bbac7b1 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebApplicationBuilderExtensions.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.TestBase; + +public static class WebApplicationBuilderExtensions +{ + public async static Task RunAbpModuleAsync(this WebApplicationBuilder builder, Action? optionsAction = null) + where TModule : IAbpModule + { + var assemblyName = typeof(TModule).Assembly.GetName()?.Name; + if (!assemblyName.IsNullOrWhiteSpace()) + { + // Set the application name as the assembly name of the module will automatically add assembly to the ApplicationParts of MVC application. + builder.Environment.ApplicationName = assemblyName!; + } + builder.Host.UseAutofac(); + await builder.AddApplicationAsync(optionsAction); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs index 83deaef26a..0c797a8dc2 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs @@ -98,13 +98,13 @@ public class AbpAuditingMiddleware : IMiddleware, ITransientDependency { return false; } - - if (!AuditingOptions.IsEnabledForIntegrationServices && + + if (!AuditingOptions.IsEnabledForIntegrationServices && context.Request.Path.Value.StartsWith($"/{AbpAspNetCoreConsts.DefaultIntegrationServiceApiPrefix}/")) { return true; } - + if (AspNetCoreAuditingOptions.IgnoredUrls.Any(x => context.Request.Path.Value.StartsWith(x))) { return true; @@ -134,7 +134,8 @@ public class AbpAuditingMiddleware : IMiddleware, ITransientDependency } if (!AuditingOptions.IsEnabledForGetRequests && - string.Equals(httpContext.Request.Method, HttpMethods.Get, StringComparison.OrdinalIgnoreCase)) + (string.Equals(httpContext.Request.Method, HttpMethods.Get, StringComparison.OrdinalIgnoreCase) || + string.Equals(httpContext.Request.Method, HttpMethods.Head, StringComparison.OrdinalIgnoreCase))) { return false; } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogScope.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogScope.cs index 8e9f14e976..e3e8f22d0a 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogScope.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogScope.cs @@ -1,9 +1,6 @@ -using JetBrains.Annotations; - -namespace Volo.Abp.Auditing; +namespace Volo.Abp.Auditing; public interface IAuditLogScope { - [NotNull] AuditLogInfo Log { get; } } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs index a1091b8600..c496a22340 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs @@ -1,6 +1,4 @@ -using JetBrains.Annotations; - -namespace Volo.Abp.Auditing; +namespace Volo.Abp.Auditing; public interface IAuditingManager { diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleObjectExtensions.cs similarity index 96% rename from framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs rename to framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleObjectExtensions.cs index 58047f575d..ea746500d6 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleObjectExtensions.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; -using Volo.Abp; using Volo.Abp.AutoMapper; using Volo.Abp.Data; using Volo.Abp.ObjectExtending; namespace AutoMapper; -public static class AbpAutoMapperExtensibleDtoExtensions +public static class AbpAutoMapperExtensibleObjectExtensions { public static IMappingExpression MapExtraProperties( this IMappingExpression mappingExpression, diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/AzureServiceBusMessageConsumerFactory.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/AzureServiceBusMessageConsumerFactory.cs index 04c7b48c6a..cf92ed7b73 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/AzureServiceBusMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/AzureServiceBusMessageConsumerFactory.cs @@ -14,7 +14,7 @@ public class AzureServiceBusMessageConsumerFactory : IAzureServiceBusMessageCons ServiceScope = serviceScopeFactory.CreateScope(); } - public IAzureServiceBusMessageConsumer CreateMessageConsumer(string topicName, string subscriptionName, string connectionName) + public IAzureServiceBusMessageConsumer CreateMessageConsumer(string topicName, string subscriptionName, string? connectionName) { var processor = ServiceScope.ServiceProvider.GetRequiredService(); processor.Initialize(topicName, subscriptionName, connectionName); diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/ConnectionPool.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/ConnectionPool.cs index d616e1264f..df830cde7a 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/ConnectionPool.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/ConnectionPool.cs @@ -28,7 +28,7 @@ public class ConnectionPool : IConnectionPool, ISingletonDependency Logger = new NullLogger(); } - public ServiceBusClient GetClient(string connectionName) + public ServiceBusClient GetClient(string? connectionName) { connectionName ??= AzureServiceBusConnections.DefaultConnectionName; return _clients.GetOrAdd( @@ -40,7 +40,7 @@ public class ConnectionPool : IConnectionPool, ISingletonDependency ).Value; } - public ServiceBusAdministrationClient GetAdministrationClient(string connectionName) + public ServiceBusAdministrationClient GetAdministrationClient(string? connectionName) { connectionName ??= AzureServiceBusConnections.DefaultConnectionName; return _adminClients.GetOrAdd( diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IAzureServiceBusMessageConsumerFactory.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IAzureServiceBusMessageConsumerFactory.cs index bd770e2204..4d93bcf5c3 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IAzureServiceBusMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IAzureServiceBusMessageConsumerFactory.cs @@ -16,5 +16,5 @@ public interface IAzureServiceBusMessageConsumerFactory IAzureServiceBusMessageConsumer CreateMessageConsumer( string topicName, string subscriptionName, - string connectionName); + string? connectionName); } diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IConnectionPool.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IConnectionPool.cs index a4cdfbc122..825c981a00 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IConnectionPool.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IConnectionPool.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.AzureServiceBus; public interface IConnectionPool : IAsyncDisposable { - ServiceBusClient GetClient(string connectionName); + ServiceBusClient GetClient(string? connectionName); - ServiceBusAdministrationClient GetAdministrationClient(string connectionName); + ServiceBusAdministrationClient GetAdministrationClient(string? connectionName); } diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IPublisherPool.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IPublisherPool.cs index 4940d250dd..bb0bf8e827 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IPublisherPool.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/IPublisherPool.cs @@ -6,5 +6,5 @@ namespace Volo.Abp.AzureServiceBus; public interface IPublisherPool : IAsyncDisposable { - Task GetAsync(string topicName, string connectionName); + Task GetAsync(string topicName, string? connectionName); } diff --git a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/PublisherPool.cs b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/PublisherPool.cs index 45b025cc59..a10c63868d 100644 --- a/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/PublisherPool.cs +++ b/framework/src/Volo.Abp.AzureServiceBus/Volo/Abp/AzureServiceBus/PublisherPool.cs @@ -24,7 +24,7 @@ public class PublisherPool : IPublisherPool, ISingletonDependency Logger = new NullLogger(); } - public async Task GetAsync(string topicName, string connectionName) + public async Task GetAsync(string topicName, string? connectionName) { var admin = _connectionPool.GetAdministrationClient(connectionName); await admin.SetupTopicAsync(topicName); 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 676b42081f..a672b0b563 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 @@ -98,6 +98,7 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien Logger.LogInformation($"'{projectName}' has been successfully created to '{projectArgs.OutputFolder}'"); ConfigureNpmPackagesForTheme(projectArgs); + await CreateOpenIddictPfxFilesAsync(projectArgs); await RunGraphBuildForMicroserviceServiceTemplate(projectArgs); await CreateInitialMigrationsAsync(projectArgs); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs index 3e83cd818d..cf697fd899 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs @@ -16,6 +16,7 @@ using Volo.Abp.Cli.LIbs; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.ProjectBuilding.Building; using Volo.Abp.Cli.ProjectBuilding.Events; +using Volo.Abp.Cli.ProjectBuilding.Templates; using Volo.Abp.Cli.ProjectBuilding.Templates.App; using Volo.Abp.Cli.ProjectBuilding.Templates.Microservice; using Volo.Abp.Cli.ProjectBuilding.Templates.Module; @@ -481,6 +482,36 @@ public abstract class ProjectCreationCommandBase await InitialMigrationCreator.CreateAsync(Path.GetDirectoryName(efCoreProjectPath), isLayeredTemplate); } + protected Task CreateOpenIddictPfxFilesAsync(ProjectBuildArgs projectArgs) + { + var module = projectArgs.ExtraProperties[nameof(RandomizeAuthServerPassPhraseStep)]; + if (string.IsNullOrWhiteSpace(module)) + { + return Task.CompletedTask; + } + + var moduleDirectory = projectArgs.OutputFolder + module; + if (projectArgs.UiFramework != UiFramework.Angular) + { + moduleDirectory = moduleDirectory.Replace("/aspnet-core/", "/"); + } + + moduleDirectory = Path.GetDirectoryName(projectArgs.SolutionName.CompanyName == null + ? moduleDirectory.Replace("MyCompanyName.MyProjectName", projectArgs.SolutionName.ProjectName) + : moduleDirectory.Replace("MyCompanyName", projectArgs.SolutionName.CompanyName).Replace("MyProjectName", projectArgs.SolutionName.ProjectName)); + + if (Directory.Exists(moduleDirectory)) + { + Logger.LogInformation($"Creating openiddict.pfx file on {moduleDirectory}"); + CmdHelper.RunCmd($"dotnet dev-certs https -ep openiddict.pfx -p {RandomizeAuthServerPassPhraseStep.RandomOpenIddictPassword}", moduleDirectory); + } + else + { + Logger.LogWarning($"Couldn't find the module directory to create openiddict.pfx file: {moduleDirectory}"); + } + return Task.CompletedTask; + } + protected async Task ConfigurePwaSupportForAngular(ProjectBuildArgs projectArgs) { var isAngular = projectArgs.UiFramework == UiFramework.Angular; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs index 7d42977c97..a41c870f41 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Volo.Abp.Cli.ProjectBuilding.Building; @@ -6,16 +7,30 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates; public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep { - protected const string DefaultPassPhrase = "00000000-0000-0000-0000-000000000000"; + private const string DefaultPassword = "00000000-0000-0000-0000-000000000000"; + private const string KestrelCertificatesDefaultPassword = "Kestrel__Certificates__Default__Password=00000000-0000-0000-0000-000000000000"; + private const string LocalhostPfx = "localhost.pfx -p 00000000-0000-0000-0000-000000000000"; + private const string DotnetDevCerts = "openiddict.pfx -p 00000000-0000-0000-0000-000000000000"; + private const string ProductionEncryptionAndSigningCertificate = "AddProductionEncryptionAndSigningCertificate(\"openiddict.pfx\", \"00000000-0000-0000-0000-000000000000\");"; + private readonly static string RandomPassword = Guid.NewGuid().ToString("D"); + public readonly static string RandomOpenIddictPassword = Guid.NewGuid().ToString("D"); public override void Execute(ProjectBuildContext context) { var files = context.Files .Where(x => !x.IsDirectory) - .Where(x => x.Content.IndexOf(DefaultPassPhrase, StringComparison.InvariantCultureIgnoreCase) >= 0) + .Where(x => x.Name.EndsWith(".cs") || + x.Name.EndsWith(".json") || + x.Name.EndsWith(".yml") || + x.Name.EndsWith(".yaml") || + x.Name.EndsWith(".md") || + x.Name.EndsWith(".ps1") || + x.Name.EndsWith(".sh") || + x.Name.Contains("Dockerfile")) + .Where(x => x.Content.IndexOf(DefaultPassword, StringComparison.InvariantCultureIgnoreCase) >= 0) .ToList(); - var randomPassPhrase = Guid.NewGuid().ToString("D"); + string module = null; foreach (var file in files) { file.NormalizeLineEndings(); @@ -23,13 +38,43 @@ public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep var lines = file.GetLines(); for (var i = 0; i < lines.Length; i++) { - if (lines[i].Contains(DefaultPassPhrase)) + if (lines[i].Contains(KestrelCertificatesDefaultPassword)) { - lines[i] = lines[i].Replace(DefaultPassPhrase, randomPassPhrase); + lines[i] = lines[i].Replace(KestrelCertificatesDefaultPassword, + KestrelCertificatesDefaultPassword.Replace(DefaultPassword, + RandomPassword)); + } + + if (lines[i].Contains(LocalhostPfx)) + { + lines[i] = lines[i].Replace(LocalhostPfx, + LocalhostPfx.Replace(DefaultPassword, + RandomPassword)); + } + + if (lines[i].Contains(DotnetDevCerts)) + { + lines[i] = lines[i].Replace(DotnetDevCerts, + DotnetDevCerts.Replace(DefaultPassword, + RandomOpenIddictPassword)); + } + + if (lines[i].Contains(ProductionEncryptionAndSigningCertificate)) + { + lines[i] = lines[i].Replace(ProductionEncryptionAndSigningCertificate, + ProductionEncryptionAndSigningCertificate.Replace(DefaultPassword, + RandomOpenIddictPassword)); + + module = file.Name; } } file.SetLines(lines); } + + if (!module.IsNullOrWhiteSpace()) + { + context.BuildArgs.ExtraProperties[nameof(RandomizeAuthServerPassPhraseStep)] = module; + } } } 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 535b68ef59..ba85c48aeb 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 @@ -22,6 +22,7 @@ using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Local; using Volo.Abp.Json; +using System.Text.RegularExpressions; namespace Volo.Abp.Cli.ProjectModification; @@ -114,12 +115,11 @@ public class SolutionModuleAdder : ITransientDependency var projectFiles = ProjectFinder.GetProjectFiles(solutionFile); await AddNugetAndNpmReferences(module, projectFiles, !(newTemplate || newProTemplate)); - + var modulesFolderInSolution = Path.Combine(Path.GetDirectoryName(solutionFile), "modules"); if (withSourceCode || newTemplate || newProTemplate) { - await PublishEventAsync(5, $"Downloading source code of {moduleName}"); await DownloadSourceCodesToSolutionFolder(module, modulesFolderInSolution, version, newTemplate, newProTemplate); @@ -147,6 +147,8 @@ public class SolutionModuleAdder : ITransientDependency else { await AddAngularPackages(solutionFile, module); + + await TryConfigureModuleConfigurationsForAngular(solutionFile, module); } await RunBundleForBlazorAsync(projectFiles, module); @@ -167,10 +169,83 @@ public class SolutionModuleAdder : ITransientDependency return module; } + private async Task TryConfigureModuleConfigurationsForAngular(string solutionFilePath, ModuleWithMastersInfo module) + { + var angularPath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(solutionFilePath)), "angular"); + + if (!Directory.Exists(angularPath)) + { + return; + } + + var angularPackages = module.NpmPackages? + .Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Angular)) + .ToList(); + + if (!angularPackages.Any()) + { + return; + } + + await PublishEventAsync(6, "Configuring angular projects..."); + + var moduleName = module.Name.Split('.').Last(); + + ConfigureAngularPackagesForAppModuleFile(angularPath, angularPackages, moduleName); + + ConfigureAngularPackagesForAppRoutingModuleFile(angularPath, angularPackages, moduleName); + } + + private void ConfigureAngularPackagesForAppModuleFile(string angularPath, List angularPackages, string moduleName) + { + var appModulePath = Path.Combine(angularPath, "src", "app", "app.module.ts"); + if (!File.Exists(appModulePath)) + { + return; + } + + var appModuleFileContent = File.ReadAllText(appModulePath); + + foreach (var angularPackage in angularPackages) + { + var moduleNameAsConfigPath = angularPackage.Name.EnsureStartsWith('@').EnsureEndsWith('/') + "config"; + + appModuleFileContent = "import { " + moduleName + "ConfigModule } from '" + moduleNameAsConfigPath + "';" + Environment.NewLine + appModuleFileContent; + appModuleFileContent = Regex.Replace(appModuleFileContent, "imports\\s*:\\s*\\[", + "imports: [" + Environment.NewLine + + " " + moduleName + "ConfigModule.forRoot(),"); + } + + File.WriteAllText(appModulePath, appModuleFileContent); + } + + private void ConfigureAngularPackagesForAppRoutingModuleFile(string angularPath, List angularPackages, string moduleName) + { + var appRoutingModulePath = Path.Combine(angularPath, "src", "app", "app-routing.module.ts"); + if (!File.Exists(appRoutingModulePath)) + { + return; + } + + var appRoutingModuleFileContent = File.ReadAllText(appRoutingModulePath); + + foreach (var angularPackage in angularPackages) + { + appRoutingModuleFileContent = Regex.Replace(appRoutingModuleFileContent, "Routes\\s*=\\s*\\[", + "Routes = [" + Environment.NewLine + + " " + "{" + Environment.NewLine + + " " + "path: '" + moduleName.ToLower() + "'," + Environment.NewLine + + " " + "loadChildren: () => " + $"import('{angularPackage.Name.EnsureStartsWith('@')}').then(m => m.{moduleName}Module.forLazy())," + Environment.NewLine + + " " + "},"); + } + + File.WriteAllText(appRoutingModulePath, appRoutingModuleFileContent); + } + private async Task SetLeptonXAbpVersionsAsync(string solutionFile, string combine) { var abpVersion = SolutionPackageVersionFinder.FindByCsprojVersion(solutionFile); - + var projects = Directory.GetFiles(Path.GetDirectoryName(solutionFile)!, "*.csproj", SearchOption.AllDirectories); foreach (var project in projects) @@ -183,7 +258,8 @@ public class SolutionModuleAdder : ITransientDependency private async Task PublishEventAsync(int currentStep, string message) { - await LocalEventBus.PublishAsync(new ModuleInstallingProgressEvent { + await LocalEventBus.PublishAsync(new ModuleInstallingProgressEvent + { CurrentStep = currentStep, Message = message }, false); @@ -562,7 +638,7 @@ public class SolutionModuleAdder : ITransientDependency if (webPackagesWillBeAddedToBlazorServerProject) { - if ( nugetTarget == NuGetPackageTarget.Web) + if (nugetTarget == NuGetPackageTarget.Web) { nugetTarget = NuGetPackageTarget.BlazorServer; } @@ -636,7 +712,7 @@ public class SolutionModuleAdder : ITransientDependency } var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj")) - ?? projectFiles.FirstOrDefault(p => p.EndsWith(".EntityFrameworkCore.csproj")) ; + ?? projectFiles.FirstOrDefault(p => p.EndsWith(".EntityFrameworkCore.csproj")); if (dbMigrationsProject == null) { diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index c7153264ae..3d44fa988a 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -47,7 +47,7 @@ public static class AbpStringExtensions /// Indicates whether this string is null or an System.String.Empty string. /// [ContractAnnotation("str:null => true")] - public static bool IsNullOrEmpty(this string? str) + public static bool IsNullOrEmpty([System.Diagnostics.CodeAnalysis.NotNullWhen(false)]this string? str) { return string.IsNullOrEmpty(str); } @@ -56,7 +56,7 @@ public static class AbpStringExtensions /// indicates whether this string is null, empty, or consists only of white-space characters. /// [ContractAnnotation("str:null => true")] - public static bool IsNullOrWhiteSpace(this string? str) + public static bool IsNullOrWhiteSpace([System.Diagnostics.CodeAnalysis.NotNullWhen(false)]this string? str) { return string.IsNullOrWhiteSpace(str); } diff --git a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj index c250d07eee..9709051409 100644 --- a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj +++ b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj @@ -37,4 +37,10 @@ + + + all + runtime; build; native; contentfiles; analyzers + + diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs index 8602792701..3791c4202f 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs @@ -132,7 +132,7 @@ public abstract class AbstractKeyReadOnlyAppService ((IHasCreationTime)e).CreationTime); } - throw new AbpException("No sorting specified but this query requires sorting. Override the ApplyDefaultSorting method for your application service derived from AbstractKeyReadOnlyAppService!"); + throw new AbpException("No sorting specified but this query requires sorting. Override the ApplySorting or the ApplyDefaultSorting method for your application service derived from AbstractKeyReadOnlyAppService!"); } /// diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs index ba82e5bdc2..f0d23fa865 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs @@ -1,4 +1,3 @@ -using JetBrains.Annotations; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; diff --git a/framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs index c63a5442c7..a877c673f1 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; @@ -17,13 +18,13 @@ public static class ServiceCollectionRepositoryExtensions var readOnlyBasicRepositoryInterface = typeof(IReadOnlyBasicRepository<>).MakeGenericType(entityType); if (readOnlyBasicRepositoryInterface.IsAssignableFrom(repositoryImplementationType)) { - RegisterService(services, readOnlyBasicRepositoryInterface, repositoryImplementationType, replaceExisting); + RegisterService(services, readOnlyBasicRepositoryInterface, repositoryImplementationType, replaceExisting, true); //IReadOnlyRepository var readOnlyRepositoryInterface = typeof(IReadOnlyRepository<>).MakeGenericType(entityType); if (readOnlyRepositoryInterface.IsAssignableFrom(repositoryImplementationType)) { - RegisterService(services, readOnlyRepositoryInterface, repositoryImplementationType, replaceExisting); + RegisterService(services, readOnlyRepositoryInterface, repositoryImplementationType, replaceExisting, true); } //IBasicRepository @@ -48,13 +49,13 @@ public static class ServiceCollectionRepositoryExtensions var readOnlyBasicRepositoryInterfaceWithPk = typeof(IReadOnlyBasicRepository<,>).MakeGenericType(entityType, primaryKeyType); if (readOnlyBasicRepositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType)) { - RegisterService(services, readOnlyBasicRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting); + RegisterService(services, readOnlyBasicRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting, true); //IReadOnlyRepository var readOnlyRepositoryInterfaceWithPk = typeof(IReadOnlyRepository<,>).MakeGenericType(entityType, primaryKeyType); if (readOnlyRepositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType)) { - RegisterService(services, readOnlyRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting); + RegisterService(services, readOnlyRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting, true); } //IBasicRepository @@ -80,15 +81,33 @@ public static class ServiceCollectionRepositoryExtensions IServiceCollection services, Type serviceType, Type implementationType, - bool replaceExisting) + bool replaceExisting, + bool isReadOnlyRepository = false) { + ServiceDescriptor descriptor; + + if (isReadOnlyRepository) + { + services.TryAddTransient(implementationType); + descriptor = ServiceDescriptor.Transient(serviceType, provider => + { + var repository = provider.GetRequiredService(implementationType); + ObjectHelper.TrySetProperty(repository.As(), x => x.IsChangeTrackingEnabled, _ => false); + return repository; + }); + } + else + { + descriptor = ServiceDescriptor.Transient(serviceType, implementationType); + } + if (replaceExisting) { - services.Replace(ServiceDescriptor.Transient(serviceType, implementationType)); + services.Replace(descriptor); } else { - services.TryAddTransient(serviceType, implementationType); + services.TryAdd(descriptor); } } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/AbpDddDomainModule.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/AbpDddDomainModule.cs index 536e31e51f..de6632704d 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/AbpDddDomainModule.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/AbpDddDomainModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.Auditing; using Volo.Abp.Caching; using Volo.Abp.Data; +using Volo.Abp.Domain.ChangeTracking; using Volo.Abp.Domain.Repositories; using Volo.Abp.EventBus; using Volo.Abp.ExceptionHandling; @@ -30,5 +31,6 @@ public class AbpDddDomainModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.AddConventionalRegistrar(new AbpRepositoryConventionalRegistrar()); + context.Services.OnRegistered(ChangeTrackingInterceptorRegistrar.RegisterIfNeeded); } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingHelper.cs new file mode 100644 index 0000000000..d2235afd22 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingHelper.cs @@ -0,0 +1,53 @@ +using System.Linq; +using System.Reflection; +using JetBrains.Annotations; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Domain.ChangeTracking; + +public static class ChangeTrackingHelper +{ + public static bool IsEntityChangeTrackingType(TypeInfo implementationType) + { + return HasEntityChangeTrackingAttribute(implementationType) || AnyMethodHasEntityChangeTrackingAttribute(implementationType); + } + + public static bool IsEntityChangeTrackingMethod([NotNull] MethodInfo methodInfo, out EntityChangeTrackingAttribute? entityChangeTrackingAttribute) + { + Check.NotNull(methodInfo, nameof(methodInfo)); + + //Method declaration + var attrs = methodInfo.GetCustomAttributes(true).OfType().ToArray(); + if (attrs.Any()) + { + entityChangeTrackingAttribute = attrs.First(); + return true; + } + + if (methodInfo.DeclaringType != null) + { + //Class declaration + attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType().ToArray(); + if (attrs.Any()) + { + entityChangeTrackingAttribute = attrs.First(); + return true; + } + } + + entityChangeTrackingAttribute = null; + return false; + } + + private static bool AnyMethodHasEntityChangeTrackingAttribute(TypeInfo implementationType) + { + return implementationType + .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Any(HasEntityChangeTrackingAttribute); + } + + private static bool HasEntityChangeTrackingAttribute(MemberInfo memberInfo) + { + return memberInfo.IsDefined(typeof(EntityChangeTrackingAttribute), true); + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptor.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptor.cs new file mode 100644 index 0000000000..307e2dee6a --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptor.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Domain.ChangeTracking; + +public class ChangeTrackingInterceptor : AbpInterceptor, ITransientDependency +{ + private readonly IEntityChangeTrackingProvider _entityChangeTrackingProvider; + + public ChangeTrackingInterceptor(IEntityChangeTrackingProvider entityChangeTrackingProvider) + { + _entityChangeTrackingProvider = entityChangeTrackingProvider; + } + + public async override Task InterceptAsync(IAbpMethodInvocation invocation) + { + if (!ChangeTrackingHelper.IsEntityChangeTrackingMethod(invocation.Method, out var changeTrackingAttribute)) + { + await invocation.ProceedAsync(); + return; + } + + using (_entityChangeTrackingProvider.Change(changeTrackingAttribute?.IsEnabled)) + { + await invocation.ProceedAsync(); + } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptorRegistrar.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptorRegistrar.cs new file mode 100644 index 0000000000..0249c570dd --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/ChangeTrackingInterceptorRegistrar.cs @@ -0,0 +1,22 @@ +using System; +using System.Reflection; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Domain.ChangeTracking; + +public class ChangeTrackingInterceptorRegistrar +{ + public static void RegisterIfNeeded(IOnServiceRegistredContext context) + { + if (ShouldIntercept(context.ImplementationType)) + { + context.Interceptors.TryAdd(); + } + } + + private static bool ShouldIntercept(Type type) + { + return !DynamicProxyIgnoreTypes.Contains(type) && ChangeTrackingHelper.IsEntityChangeTrackingType(type.GetTypeInfo()); + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/DisableEntityChangeTrackingAttribute.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/DisableEntityChangeTrackingAttribute.cs new file mode 100644 index 0000000000..98011bda5f --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/DisableEntityChangeTrackingAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Volo.Abp.Domain.ChangeTracking; + +/// +/// Ensures that the change tracking in enabled for the given method or class. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public class DisableEntityChangeTrackingAttribute : EntityChangeTrackingAttribute +{ + public DisableEntityChangeTrackingAttribute() + : base(false) + { + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EnableEntityChangeTrackingAttribute.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EnableEntityChangeTrackingAttribute.cs new file mode 100644 index 0000000000..542b60cd74 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EnableEntityChangeTrackingAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Volo.Abp.Domain.ChangeTracking; + +/// +/// Ensures that the change tracking in enabled for the given method or class. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public class EnableEntityChangeTrackingAttribute : EntityChangeTrackingAttribute +{ + public EnableEntityChangeTrackingAttribute() + : base(true) + { + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EntityChangeTrackingAttribute.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EntityChangeTrackingAttribute.cs new file mode 100644 index 0000000000..3446a49354 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/ChangeTracking/EntityChangeTrackingAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.Domain.ChangeTracking; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public abstract class EntityChangeTrackingAttribute : Attribute +{ + public virtual bool IsEnabled { get; set; } + + public EntityChangeTrackingAttribute(bool isEnabled) + { + IsEnabled = isEnabled; + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs index 0d86045eea..cd85acce50 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; @@ -34,6 +36,14 @@ public abstract class BasicRepositoryBase : public ICancellationTokenProvider CancellationTokenProvider => LazyServiceProvider.LazyGetService(NullCancellationTokenProvider.Instance); + public ILoggerFactory? LoggerFactory => LazyServiceProvider.LazyGetService(); + + public ILogger Logger => LazyServiceProvider.LazyGetService(provider => LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance); + + public IEntityChangeTrackingProvider EntityChangeTrackingProvider => LazyServiceProvider.LazyGetRequiredService(); + + public bool? IsChangeTrackingEnabled { get; protected set; } + protected BasicRepositoryBase() { @@ -106,6 +116,24 @@ public abstract class BasicRepositoryBase : { return CancellationTokenProvider.FallbackToProvider(preferredValue); } + + protected virtual bool ShouldTrackingEntityChange() + { + // If IsChangeTrackingEnabled is set, it has the highest priority. This generally means the repository is read-only. + if (IsChangeTrackingEnabled.HasValue) + { + return IsChangeTrackingEnabled.Value; + } + + // If Interface/Class/Method has Enable/DisableEntityChangeTrackingAttribute, it has the second highest priority. + if (EntityChangeTrackingProvider.Enabled.HasValue) + { + return EntityChangeTrackingProvider.Enabled.Value; + } + + // Default behavior is tracking entity change. + return true; + } } public abstract class BasicRepositoryBase : BasicRepositoryBase, IBasicRepository diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/EntityChangeTrackingProvider.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/EntityChangeTrackingProvider.cs new file mode 100644 index 0000000000..19c10e9a3f --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/EntityChangeTrackingProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Domain.Repositories; + +public class EntityChangeTrackingProvider : IEntityChangeTrackingProvider, ISingletonDependency +{ + public bool? Enabled => _current.Value; + + private readonly AsyncLocal _current = new AsyncLocal(); + + public IDisposable Change(bool? enabled) + { + var previousValue = Enabled; + _current.Value = enabled; + return new DisposeAction(() => _current.Value = previousValue); + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IEntityChangeTrackingProvider.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IEntityChangeTrackingProvider.cs new file mode 100644 index 0000000000..f1db1584fa --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IEntityChangeTrackingProvider.cs @@ -0,0 +1,10 @@ +using System; + +namespace Volo.Abp.Domain.Repositories; + +public interface IEntityChangeTrackingProvider +{ + bool? Enabled { get; } + + IDisposable Change(bool? enabled); +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs index 3c7ae81875..dc39255b25 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.Domain.Repositories; /// public interface IRepository { - + bool? IsChangeTrackingEnabled { get; } } public interface IRepository : IReadOnlyRepository, IBasicRepository diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/ISupportsExplicitLoading.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/ISupportsExplicitLoading.cs index 1c51954f57..08c1f2556f 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/ISupportsExplicitLoading.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/ISupportsExplicitLoading.cs @@ -7,8 +7,8 @@ using Volo.Abp.Domain.Entities; namespace Volo.Abp.Domain.Repositories; -public interface ISupportsExplicitLoading - where TEntity : class, IEntity +public interface ISupportsExplicitLoading + where TEntity : class, IEntity { Task EnsureCollectionLoadedAsync( TEntity entity, @@ -18,7 +18,7 @@ public interface ISupportsExplicitLoading Task EnsurePropertyLoadedAsync( TEntity entity, - Expression> propertyExpression, + Expression> propertyExpression, CancellationToken cancellationToken) where TProperty : class; } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs index cbebf62196..3c43798c38 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs @@ -15,16 +15,16 @@ namespace Volo.Abp.Domain.Repositories; public static class RepositoryExtensions { - public async static Task EnsureCollectionLoadedAsync( - this IBasicRepository repository, + public async static Task EnsureCollectionLoadedAsync( + this IBasicRepository repository, TEntity entity, Expression>> propertyExpression, CancellationToken cancellationToken = default ) - where TEntity : class, IEntity + where TEntity : class, IEntity where TProperty : class { - var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; + var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; if (repo != null) { await repo.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken); @@ -34,13 +34,13 @@ public static class RepositoryExtensions public async static Task EnsurePropertyLoadedAsync( this IBasicRepository repository, TEntity entity, - Expression> propertyExpression, + Expression> propertyExpression, CancellationToken cancellationToken = default ) where TEntity : class, IEntity where TProperty : class { - var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; + var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; if (repo != null) { await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken); @@ -60,12 +60,12 @@ public static class RepositoryExtensions } } - public async static Task EnsureExistsAsync( - this IRepository repository, + public async static Task EnsureExistsAsync( + this IRepository repository, Expression> expression, CancellationToken cancellationToken = default ) - where TEntity : class, IEntity + where TEntity : class, IEntity { if (!await repository.AnyAsync(expression, cancellationToken)) { @@ -145,6 +145,40 @@ public static class RepositoryExtensions } } + /// + /// Disables change tracking mechanism for the given repository. + /// + /// A repository object + /// + /// A disposable object. Dispose it to restore change tracking mechanism back to its previous state. + /// + public static IDisposable DisableTracking(this IRepository repository) + { + return Tracking(repository, false); + } + + /// + /// Enables change tracking mechanism for the given repository. + /// + /// A repository object + /// + /// A disposable object. Dispose it to restore change tracking mechanism back to its previous state. + /// + public static IDisposable EnableTracking(this IRepository repository) + { + return Tracking(repository, true); + } + + private static IDisposable Tracking(this IRepository repository, bool enabled) + { + var previous = repository.IsChangeTrackingEnabled; + ObjectHelper.TrySetProperty(ProxyHelper.UnProxy(repository).As(), x => x.IsChangeTrackingEnabled, _ => enabled); + return new DisposeAction(_ => + { + ObjectHelper.TrySetProperty(ProxyHelper.UnProxy(repository).As(), x => x.IsChangeTrackingEnabled, _ => previous); + }, repository); + } + private static IUnitOfWorkManager GetUnitOfWorkManager( this IBasicRepository repository, [CallerMemberName] string callingMethodName = nameof(GetUnitOfWorkManager) diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AdditionalEmailSendingArgs.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AdditionalEmailSendingArgs.cs new file mode 100644 index 0000000000..4de1eb6105 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AdditionalEmailSendingArgs.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Data; + +namespace Volo.Abp.Emailing; + +[Serializable] +public class AdditionalEmailSendingArgs +{ + public List? CC { get; set; } + + public List? Attachments { get; set; } + + public ExtraPropertyDictionary? ExtraProperties { get; set; } +} diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs index 07b4ca9bcd..ac12ddcead 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs @@ -15,15 +15,15 @@ public class BackgroundEmailSendingJob : AsyncBackgroundJob public bool IsBodyHtml { get; set; } = true; - //TODO: Add other properties and attachments + public AdditionalEmailSendingArgs? AdditionalEmailSendingArgs { get; set; } } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailAttachment.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailAttachment.cs new file mode 100644 index 0000000000..e2fe3a3a6b --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailAttachment.cs @@ -0,0 +1,11 @@ +using System; + +namespace Volo.Abp.Emailing; + +[Serializable] +public class EmailAttachment +{ + public string? Name { get; set; } + + public byte[]? File { get; set; } +} diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs index d8a46ca4b9..5f342b2f40 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using System.Linq; using System.Net.Mail; using System.Text; using System.Threading.Tasks; @@ -24,20 +26,44 @@ public abstract class EmailSenderBase : IEmailSender BackgroundJobManager = backgroundJobManager; } - public virtual async Task SendAsync(string to, string? subject, string? body, bool isBodyHtml = true) + public virtual async Task SendAsync(string to, string? subject, string? body, bool isBodyHtml = true, AdditionalEmailSendingArgs? additionalEmailSendingArgs = null) { - await SendAsync(new MailMessage - { - To = { to }, - Subject = subject, - Body = body, - IsBodyHtml = isBodyHtml - }); + await SendAsync(BuildMailMessage(null, to, subject, body, isBodyHtml, additionalEmailSendingArgs)); + } + + public virtual async Task SendAsync(string from, string to, string? subject, string? body, bool isBodyHtml = true, AdditionalEmailSendingArgs? additionalEmailSendingArgs = null) + { + await SendAsync(BuildMailMessage(from, to, subject, body, isBodyHtml, additionalEmailSendingArgs)); } - public virtual async Task SendAsync(string from, string to, string? subject, string? body, bool isBodyHtml = true) + protected virtual MailMessage BuildMailMessage(string? from, string to, string? subject, string? body, bool isBodyHtml = true, AdditionalEmailSendingArgs? additionalEmailSendingArgs = null) { - await SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml }); + var message = from == null + ? new MailMessage { To = { to }, Subject = subject, Body = body, IsBodyHtml = isBodyHtml } + : new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml }; + + if (additionalEmailSendingArgs != null) + { + if (additionalEmailSendingArgs.Attachments != null) + { + foreach (var attachment in additionalEmailSendingArgs.Attachments.Where(x => x.File != null)) + { + var fileStream = new MemoryStream(attachment.File!); + fileStream.Seek(0, SeekOrigin.Begin); + message.Attachments.Add(new Attachment(fileStream, attachment.Name)); + } + } + + if (additionalEmailSendingArgs.CC != null) + { + foreach (var cc in additionalEmailSendingArgs.CC) + { + message.CC.Add(cc); + } + } + } + + return message; } public virtual async Task SendAsync(MailMessage mail, bool normalize = true) @@ -50,11 +76,11 @@ public abstract class EmailSenderBase : IEmailSender await SendEmailAsync(mail); } - public virtual async Task QueueAsync(string to, string subject, string body, bool isBodyHtml = true) + public virtual async Task QueueAsync(string to, string subject, string body, bool isBodyHtml = true, AdditionalEmailSendingArgs? additionalEmailSendingArgs = null) { if (!BackgroundJobManager.IsAvailable()) { - await SendAsync(to, subject, body, isBodyHtml); + await SendAsync(to, subject, body, isBodyHtml, additionalEmailSendingArgs); return; } @@ -64,16 +90,17 @@ public abstract class EmailSenderBase : IEmailSender To = to, Subject = subject, Body = body, - IsBodyHtml = isBodyHtml + IsBodyHtml = isBodyHtml, + AdditionalEmailSendingArgs = additionalEmailSendingArgs } ); } - public virtual async Task QueueAsync(string from, string to, string subject, string body, bool isBodyHtml = true) + public virtual async Task QueueAsync(string from, string to, string subject, string body, bool isBodyHtml = true, AdditionalEmailSendingArgs? additionalEmailSendingArgs = null) { if (!BackgroundJobManager.IsAvailable()) { - await SendAsync(from, to, subject, body, isBodyHtml); + await SendAsync(from, to, subject, body, isBodyHtml, additionalEmailSendingArgs); return; } @@ -84,7 +111,8 @@ public abstract class EmailSenderBase : IEmailSender To = to, Subject = subject, Body = body, - IsBodyHtml = isBodyHtml + IsBodyHtml = isBodyHtml, + AdditionalEmailSendingArgs = additionalEmailSendingArgs } ); } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSender.cs index 55456783c4..64658b0519 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSender.cs @@ -15,7 +15,8 @@ public interface IEmailSender string to, string? subject, string? body, - bool isBodyHtml = true + bool isBodyHtml = true, + AdditionalEmailSendingArgs? additionalEmailSendingArgs = null ); /// @@ -26,7 +27,8 @@ public interface IEmailSender string to, string? subject, string? body, - bool isBodyHtml = true + bool isBodyHtml = true, + AdditionalEmailSendingArgs? additionalEmailSendingArgs = null ); /// @@ -49,7 +51,8 @@ public interface IEmailSender string to, string subject, string body, - bool isBodyHtml = true + bool isBodyHtml = true, + AdditionalEmailSendingArgs? additionalEmailSendingArgs = null ); /// @@ -60,8 +63,7 @@ public interface IEmailSender string to, string subject, string body, - bool isBodyHtml = true + bool isBodyHtml = true, + AdditionalEmailSendingArgs? additionalEmailSendingArgs = null ); - - //TODO: Add other Queue methods too. Problem: MailMessage is not serializable so can not be used in background jobs. } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs index 99a8f2e1e7..4bf7e18158 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs @@ -67,7 +67,7 @@ public class SmtpEmailSender : EmailSenderBase, ISmtpEmailSender, ITransientDepe } } - protected override async Task SendEmailAsync(MailMessage mail) + protected async override Task SendEmailAsync(MailMessage mail) { using (var smtpClient = await BuildClientAsync()) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj index b19feda6c3..d470ed692e 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.MySQL Volo.Abp.EntityFrameworkCore.MySQL $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs index 596062d533..07381983ca 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs @@ -10,7 +10,7 @@ public static class AbpDbContextConfigurationContextMySQLExtensions { public static DbContextOptionsBuilder UseMySQL( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action mySQLOptionsAction = null) + Action? mySQLOptionsAction = null) { if (context.ExistingConnection != null) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs index 247e96cee7..baf8c53a14 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs @@ -8,7 +8,7 @@ public static class AbpDbContextOptionsMySQLExtensions { public static void UseMySQL( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action mySQLOptionsAction = null) + Action? mySQLOptionsAction = null) { options.Configure(context => { @@ -18,7 +18,7 @@ public static class AbpDbContextOptionsMySQLExtensions public static void UseMySQL( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action mySQLOptionsAction = null) + Action? mySQLOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 2ead0da1f3..dcd5fb1788 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.Oracle.Devart Volo.Abp.EntityFrameworkCore.Oracle.Devart $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleDevartExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleDevartExtensions.cs index a672a280ee..e2138dd7d1 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleDevartExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleDevartExtensions.cs @@ -10,7 +10,7 @@ public static class AbpDbContextConfigurationContextOracleDevartExtensions { public static DbContextOptionsBuilder UseOracle( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action oracleOptionsAction = null, + Action? oracleOptionsAction = null, bool useExistingConnectionIfAvailable = false) { if (useExistingConnectionIfAvailable && context.ExistingConnection != null) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleDevartExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleDevartExtensions.cs index 12f5bc0437..650d222663 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleDevartExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleDevartExtensions.cs @@ -8,7 +8,7 @@ public static class AbpDbContextOptionsOracleDevartExtensions { public static void UseOracle( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action oracleOptionsAction = null, + Action? oracleOptionsAction = null, bool useExistingConnectionIfAvailable = false) { options.Configure(context => @@ -19,7 +19,7 @@ public static class AbpDbContextOptionsOracleDevartExtensions public static void UseOracle( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action oracleOptionsAction = null, + Action? oracleOptionsAction = null, bool useExistingConnectionIfAvailable = false) where TDbContext : AbpDbContext { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj index 187c6a1d9f..3ce2f5ff25 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.Oracle Volo.Abp.EntityFrameworkCore.Oracle $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs index 9b9d3b2916..39f3a5b86f 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs @@ -10,7 +10,7 @@ public static class AbpDbContextConfigurationContextOracleExtensions { public static DbContextOptionsBuilder UseOracle( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action oracleOptionsAction = null) + Action? oracleOptionsAction = null) { if (context.ExistingConnection != null) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs index cc0dc28699..8458dd6d4e 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs @@ -8,7 +8,7 @@ public static class AbpDbContextOptionsOracleExtensions { public static void UseOracle( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action oracleOptionsAction = null) + Action? oracleOptionsAction = null) { options.Configure(context => { @@ -18,7 +18,7 @@ public static class AbpDbContextOptionsOracleExtensions public static void UseOracle( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action oracleOptionsAction = null) + Action? oracleOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj index 67f55beeb4..04da1dd18a 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.PostgreSql Volo.Abp.EntityFrameworkCore.PostgreSql $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextPostgreSqlExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextPostgreSqlExtensions.cs index 7e13fb01a2..918c0629c1 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextPostgreSqlExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextPostgreSqlExtensions.cs @@ -11,14 +11,14 @@ public static class AbpDbContextConfigurationContextPostgreSqlExtensions [Obsolete("Use 'UseNpgsql(...)' method instead. This will be removed in future versions.")] public static DbContextOptionsBuilder UsePostgreSql( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) { return context.UseNpgsql(postgreSqlOptionsAction); } public static DbContextOptionsBuilder UseNpgsql( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) { if (context.ExistingConnection != null) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsPostgreSqlExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsPostgreSqlExtensions.cs index bdea54efab..2a52c5de56 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsPostgreSqlExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsPostgreSqlExtensions.cs @@ -9,7 +9,7 @@ public static class AbpDbContextOptionsPostgreSqlExtensions [Obsolete("Use 'UseNpgsql(...)' method instead. This will be removed in future versions.")] public static void UsePostgreSql( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) { options.Configure(context => { @@ -20,7 +20,7 @@ public static class AbpDbContextOptionsPostgreSqlExtensions [Obsolete("Use 'UseNpgsql(...)' method instead. This will be removed in future versions.")] public static void UsePostgreSql( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => @@ -31,7 +31,7 @@ public static class AbpDbContextOptionsPostgreSqlExtensions public static void UseNpgsql( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) { options.Configure(context => { @@ -41,7 +41,7 @@ public static class AbpDbContextOptionsPostgreSqlExtensions public static void UseNpgsql( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action postgreSqlOptionsAction = null) + Action? postgreSqlOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/ConnectionStrings/NpgsqlConnectionStringChecker.cs b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/ConnectionStrings/NpgsqlConnectionStringChecker.cs index f3ab83eb55..56e47aa2d4 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/ConnectionStrings/NpgsqlConnectionStringChecker.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo/Abp/EntityFrameworkCore/ConnectionStrings/NpgsqlConnectionStringChecker.cs @@ -25,7 +25,7 @@ public class NpgsqlConnectionStringChecker : IConnectionStringChecker, ITransien await using var conn = new NpgsqlConnection(connString.ConnectionString); await conn.OpenAsync(); result.Connected = true; - await conn.ChangeDatabaseAsync(oldDatabaseName); + await conn.ChangeDatabaseAsync(oldDatabaseName!); result.DatabaseExists = true; await conn.CloseAsync(); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj index f655b66814..0fb7ee0c61 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.SqlServer Volo.Abp.EntityFrameworkCore.SqlServer $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqlServerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqlServerExtensions.cs index 76476423bb..95ea2ebd8b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqlServerExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqlServerExtensions.cs @@ -10,7 +10,7 @@ public static class AbpDbContextConfigurationContextSqlServerExtensions { public static DbContextOptionsBuilder UseSqlServer( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action sqlServerOptionsAction = null) + Action? sqlServerOptionsAction = null) { if (context.ExistingConnection != null) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqlServerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqlServerExtensions.cs index 30bf419d5e..8981d8f0c4 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqlServerExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqlServerExtensions.cs @@ -8,7 +8,7 @@ public static class AbpDbContextOptionsSqlServerExtensions { public static void UseSqlServer( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action sqlServerOptionsAction = null) + Action? sqlServerOptionsAction = null) { options.Configure(context => { @@ -18,7 +18,7 @@ public static class AbpDbContextOptionsSqlServerExtensions public static void UseSqlServer( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action sqlServerOptionsAction = null) + Action? sqlServerOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj index 002b876343..e57c897169 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore.Sqlite Volo.Abp.EntityFrameworkCore.Sqlite $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqliteExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqliteExtensions.cs index 6dea2a336b..a4e3b60ec9 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqliteExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextSqliteExtensions.cs @@ -11,7 +11,7 @@ public static class AbpDbContextConfigurationContextSqliteExtensions { public static DbContextOptionsBuilder UseSqlite( [NotNull] this AbpDbContextConfigurationContext context, - [CanBeNull] Action sqliteOptionsAction = null) + Action? sqliteOptionsAction = null) { if (context.ExistingConnection != null) { @@ -34,7 +34,7 @@ public static class AbpDbContextConfigurationContextSqliteExtensions public static DbContextOptionsBuilder UseSqlite( [NotNull] this AbpDbContextConfigurationContext context, DbConnection connection, - [CanBeNull] Action sqliteOptionsAction = null) + Action? sqliteOptionsAction = null) { if (context.ExistingConnection != null) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqliteExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqliteExtensions.cs index aaf39cbde5..c3f24a318c 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqliteExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsSqliteExtensions.cs @@ -8,7 +8,7 @@ public static class AbpDbContextOptionsSqliteExtensions { public static void UseSqlite( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action sqliteOptionsAction = null) + Action? sqliteOptionsAction = null) { options.Configure(context => { @@ -18,7 +18,7 @@ public static class AbpDbContextOptionsSqliteExtensions public static void UseSqlite( [NotNull] this AbpDbContextOptions options, - [CanBeNull] Action sqliteOptionsAction = null) + Action? sqliteOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs index f51df050ef..55e88b72e7 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs @@ -13,7 +13,7 @@ public static class AbpEfCoreServiceCollectionExtensions { public static IServiceCollection AddAbpDbContext( this IServiceCollection services, - Action optionsBuilder = null) + Action? optionsBuilder = null) where TDbContext : AbpDbContext { services.AddMemoryCache(); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj b/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj index c547299bae..af2be88afa 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.EntityFrameworkCore Volo.Abp.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs index 94dba628d7..614ba135ff 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Entities; @@ -44,4 +45,10 @@ public static class EfCoreRepositoryExtensions throw new ArgumentException("Given repository does not implement " + typeof(IEfCoreRepository).AssemblyQualifiedName, nameof(repository)); } + + public static IQueryable AsNoTrackingIf(this IQueryable queryable, bool condition) + where TEntity : class, IEntity + { + return condition ? queryable.AsNoTracking() : queryable; + } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 03af8d1fb4..3274360ba2 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -1,4 +1,3 @@ -using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -6,16 +5,16 @@ using System; using System.Collections.Generic; using System.Data; using System.Linq; -using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Logging; +using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; using Volo.Abp.Guids; -using Volo.Abp.MultiTenancy; namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -27,11 +26,11 @@ public class EfCoreRepository : RepositoryBase, IE protected virtual TDbContext DbContext => GetDbContext(); [Obsolete("Use GetDbContextAsync() method.")] - DbContext IEfCoreRepository.DbContext => GetDbContext() as DbContext; + DbContext IEfCoreRepository.DbContext => (GetDbContext() as DbContext)!; async Task IEfCoreRepository.GetDbContextAsync() { - return await GetDbContextAsync() as DbContext; + return (await GetDbContextAsync() as DbContext)!; } [Obsolete("Use GetDbContextAsync() method.")] @@ -75,13 +74,13 @@ public class EfCoreRepository : RepositoryBase, IE { return (await GetDbContextAsync()).Set(); } - + protected async Task GetDbConnectionAsync() { return (await GetDbContextAsync()).Database.GetDbConnection(); } - protected async Task GetDbTransactionAsync() + protected async Task GetDbTransactionAsync() { return (await GetDbContextAsync()).Database.CurrentTransaction?.GetDbTransaction(); } @@ -93,7 +92,7 @@ public class EfCoreRepository : RepositoryBase, IE public virtual IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService(SimpleGuidGenerator.Instance); - public IEfCoreBulkOperationProvider BulkOperationProvider => LazyServiceProvider.LazyGetService(); + public IEfCoreBulkOperationProvider? BulkOperationProvider => LazyServiceProvider.LazyGetService(); public EfCoreRepository(IDbContextProvider dbContextProvider) { @@ -254,19 +253,19 @@ public class EfCoreRepository : RepositoryBase, IE { return includeDetails ? await (await WithDetailsAsync()).ToListAsync(GetCancellationToken(cancellationToken)) - : await (await GetDbSetAsync()).ToListAsync(GetCancellationToken(cancellationToken)); + : await (await GetQueryableAsync()).ToListAsync(GetCancellationToken(cancellationToken)); } public async override Task> GetListAsync(Expression> predicate, bool includeDetails = false, CancellationToken cancellationToken = default) { return includeDetails ? await (await WithDetailsAsync()).Where(predicate).ToListAsync(GetCancellationToken(cancellationToken)) - : await (await GetDbSetAsync()).Where(predicate).ToListAsync(GetCancellationToken(cancellationToken)); + : await (await GetQueryableAsync()).Where(predicate).ToListAsync(GetCancellationToken(cancellationToken)); } public async override Task GetCountAsync(CancellationToken cancellationToken = default) { - return await (await GetDbSetAsync()).LongCountAsync(GetCancellationToken(cancellationToken)); + return await (await GetQueryableAsync()).LongCountAsync(GetCancellationToken(cancellationToken)); } public async override Task> GetPagedListAsync( @@ -278,7 +277,7 @@ public class EfCoreRepository : RepositoryBase, IE { var queryable = includeDetails ? await WithDetailsAsync() - : await GetDbSetAsync(); + : await GetQueryableAsync(); return await queryable .OrderByIf>(!sorting.IsNullOrWhiteSpace(), sorting) @@ -289,12 +288,12 @@ public class EfCoreRepository : RepositoryBase, IE [Obsolete("Use GetQueryableAsync method.")] protected override IQueryable GetQueryable() { - return DbSet.AsQueryable(); + return DbSet.AsQueryable().AsNoTrackingIf(!ShouldTrackingEntityChange()); } public async override Task> GetQueryableAsync() { - return (await GetDbSetAsync()).AsQueryable(); + return (await GetDbSetAsync()).AsQueryable().AsNoTrackingIf(!ShouldTrackingEntityChange()); } protected async override Task SaveChangesAsync(CancellationToken cancellationToken) @@ -302,7 +301,7 @@ public class EfCoreRepository : RepositoryBase, IE await (await GetDbContextAsync()).SaveChangesAsync(cancellationToken); } - public async override Task FindAsync( + public async override Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -311,7 +310,7 @@ public class EfCoreRepository : RepositoryBase, IE ? await (await WithDetailsAsync()) .Where(predicate) .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)) - : await (await GetDbSetAsync()) + : await (await GetQueryableAsync()) .Where(predicate) .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)); } @@ -333,7 +332,7 @@ public class EfCoreRepository : RepositoryBase, IE } } - public override async Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) + public async override Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) { var dbContext = await GetDbContextAsync(); var dbSet = dbContext.Set(); @@ -354,7 +353,7 @@ public class EfCoreRepository : RepositoryBase, IE public virtual async Task EnsurePropertyLoadedAsync( TEntity entity, - Expression> propertyExpression, + Expression> propertyExpression, CancellationToken cancellationToken = default) where TProperty : class { @@ -442,7 +441,7 @@ public class EfCoreRepository : RepositoryBase, IE public class EfCoreRepository : EfCoreRepository, IEfCoreRepository, - ISupportsExplicitLoading + ISupportsExplicitLoading where TDbContext : IEfCoreDbContext where TEntity : class, IEntity @@ -465,11 +464,13 @@ public class EfCoreRepository : EfCoreRepository FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { return includeDetails - ? await (await WithDetailsAsync()).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)) - : await (await GetDbSetAsync()).FindAsync(new object[] { id }, GetCancellationToken(cancellationToken)); + ? await (await WithDetailsAsync()).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id!.Equals(id), GetCancellationToken(cancellationToken)) + : !ShouldTrackingEntityChange() + ? await (await GetQueryableAsync()).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id!.Equals(id), GetCancellationToken(cancellationToken)) + : await (await GetDbSetAsync()).FindAsync(new object[] {id!}, GetCancellationToken(cancellationToken)); } public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index bc93ca97b8..05dd4527fc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -37,7 +37,7 @@ namespace Volo.Abp.EntityFrameworkCore; public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, ITransientDependency where TDbContext : DbContext { - public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; protected virtual Guid? CurrentTenantId => CurrentTenant?.Id; @@ -74,21 +74,21 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, .GetMethod( nameof(ConfigureBaseProperties), BindingFlags.Instance | BindingFlags.NonPublic - ); + )!; private static readonly MethodInfo ConfigureValueConverterMethodInfo = typeof(AbpDbContext) .GetMethod( nameof(ConfigureValueConverter), BindingFlags.Instance | BindingFlags.NonPublic - ); + )!; private static readonly MethodInfo ConfigureValueGeneratedMethodInfo = typeof(AbpDbContext) .GetMethod( nameof(ConfigureValueGenerated), BindingFlags.Instance | BindingFlags.NonPublic - ); + )!; protected AbpDbContext(DbContextOptions options) : base(options) @@ -157,7 +157,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, try { var auditLog = AuditingManager?.Current?.Log; - List entityChangeList = null; + List? entityChangeList = null; if (auditLog != null) { entityChangeList = EntityHistoryHelper.CreateChangeList(ChangeTracker.Entries().ToList()); @@ -174,7 +174,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, if (entityChangeList != null) { EntityHistoryHelper.UpdateChangeList(entityChangeList); - auditLog.EntityChanges.AddRange(entityChangeList); + auditLog!.EntityChanges.AddRange(entityChangeList); Logger.LogDebug($"Added {entityChangeList.Count} entity changes to the current audit log"); } @@ -249,13 +249,13 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, } } - protected virtual void ChangeTracker_Tracked(object sender, EntityTrackedEventArgs e) + protected virtual void ChangeTracker_Tracked(object? sender, EntityTrackedEventArgs e) { FillExtraPropertiesForTrackedEntities(e); PublishEventsForTrackedEntity(e.Entry); } - protected virtual void ChangeTracker_StateChanged(object sender, EntityStateChangedEventArgs e) + protected virtual void ChangeTracker_StateChanged(object? sender, EntityStateChangedEventArgs e) { PublishEventsForTrackedEntity(e.Entry); } @@ -453,11 +453,11 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, if (conversionType == typeof(Guid)) { - entryProperty.CurrentValue = TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(entityProperty.ToString()); + entryProperty.CurrentValue = TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(entityProperty.ToString()!); } else if (conversionType.IsEnum) { - entryProperty.CurrentValue = Enum.Parse(conversionType, entityProperty.ToString(), ignoreCase: true); + entryProperty.CurrentValue = Enum.Parse(conversionType, entityProperty.ToString()!, ignoreCase: true); } else { @@ -560,7 +560,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, return; } - var idProperty = entry.Property("Id").Metadata.PropertyInfo; + var idProperty = entry.Property("Id").Metadata.PropertyInfo!; //Check for DatabaseGeneratedAttribute var dbGeneratedAttr = ReflectionHelper @@ -669,7 +669,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, } var idPropertyBuilder = modelBuilder.Entity().Property(x => ((IEntity)x).Id); - if (idPropertyBuilder.Metadata.PropertyInfo.IsDefined(typeof(DatabaseGeneratedAttribute), true)) + if (idPropertyBuilder.Metadata.PropertyInfo!.IsDefined(typeof(DatabaseGeneratedAttribute), true)) { return; } @@ -692,10 +692,10 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, return false; } - protected virtual Expression> CreateFilterExpression() + protected virtual Expression>? CreateFilterExpression() where TEntity : class { - Expression> expression = null; + Expression>? expression = null; if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs index 43803b4004..cb5b258192 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs @@ -12,7 +12,7 @@ public class AbpDbContextOptions { internal List> DefaultPreConfigureActions { get; } - internal Action DefaultConfigureAction { get; set; } + internal Action? DefaultConfigureAction { get; set; } internal Dictionary> PreConfigureActions { get; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs index 8d60d6d3c9..34a7dd008d 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs @@ -14,17 +14,17 @@ public class AbpDbContextConfigurationContext : IServiceProviderAccessor public string ConnectionString { get; } - public string ConnectionStringName { get; } + public string? ConnectionStringName { get; } - public DbConnection ExistingConnection { get; } + public DbConnection? ExistingConnection { get; } public DbContextOptionsBuilder DbContextOptions { get; protected set; } public AbpDbContextConfigurationContext( [NotNull] string connectionString, [NotNull] IServiceProvider serviceProvider, - [CanBeNull] string connectionStringName, - [CanBeNull] DbConnection existingConnection) + string? connectionStringName, + DbConnection? existingConnection) { ConnectionString = connectionString; ServiceProvider = serviceProvider; @@ -45,8 +45,8 @@ public class AbpDbContextConfigurationContext : AbpDbContextConfigur public AbpDbContextConfigurationContext( string connectionString, [NotNull] IServiceProvider serviceProvider, - [CanBeNull] string connectionStringName, - [CanBeNull] DbConnection existingConnection) + string? connectionStringName, + DbConnection? existingConnection) : base( connectionString, serviceProvider, diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpEntityOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpEntityOptions.cs index a2c75fe5c3..ecd98356c3 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpEntityOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpEntityOptions.cs @@ -11,7 +11,7 @@ public class AbpEntityOptions { public static AbpEntityOptions Empty { get; } = new AbpEntityOptions(); - public Func, IQueryable> DefaultWithDetailsFunc { get; set; } + public Func, IQueryable>? DefaultWithDetailsFunc { get; set; } } public class AbpEntityOptions @@ -23,7 +23,7 @@ public class AbpEntityOptions _options = new Dictionary(); } - public AbpEntityOptions GetOrNull() + public AbpEntityOptions? GetOrNull() where TEntity : IEntity { return _options.GetOrDefault(typeof(TEntity)) as AbpEntityOptions; @@ -35,10 +35,10 @@ public class AbpEntityOptions Check.NotNull(optionsAction, nameof(optionsAction)); optionsAction( - _options.GetOrAdd( + (_options.GetOrAdd( typeof(TEntity), () => new AbpEntityOptions() - ) as AbpEntityOptions + ) as AbpEntityOptions)! ); } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs index 311cca1153..a7ea24a778 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs @@ -6,14 +6,14 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection; public class DbContextCreationContext { - public static DbContextCreationContext Current => _current.Value; + public static DbContextCreationContext Current => _current.Value!; private static readonly AsyncLocal _current = new AsyncLocal(); public string ConnectionStringName { get; } public string ConnectionString { get; } - public DbConnection ExistingConnection { get; internal set; } + public DbConnection? ExistingConnection { get; internal set; } public DbContextCreationContext(string connectionStringName, string connectionString) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs index eb51c4843f..1b3a6f48b5 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs @@ -43,7 +43,7 @@ public static class DbContextOptionsFactory var preConfigureActions = options.PreConfigureActions.GetOrDefault(typeof(TDbContext)); if (!preConfigureActions.IsNullOrEmpty()) { - foreach (var preConfigureAction in preConfigureActions) + foreach (var preConfigureAction in preConfigureActions!) { ((Action>)preConfigureAction).Invoke(context); } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/IncomingEventRecord.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/IncomingEventRecord.cs index 986c19bbbf..6d151851c4 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/IncomingEventRecord.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/IncomingEventRecord.cs @@ -15,11 +15,11 @@ public class IncomingEventRecord : public ExtraPropertyDictionary ExtraProperties { get; private set; } - public string MessageId { get; private set; } + public string MessageId { get; private set; } = default!; - public string EventName { get; private set; } + public string EventName { get; private set; } = default!; - public byte[] EventData { get; private set; } + public byte[] EventData { get; private set; } = default!; public DateTime CreationTime { get; private set; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/OutgoingEventRecord.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/OutgoingEventRecord.cs index fe639411a2..163e90e26d 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/OutgoingEventRecord.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DistributedEvents/OutgoingEventRecord.cs @@ -15,9 +15,9 @@ public class OutgoingEventRecord : public ExtraPropertyDictionary ExtraProperties { get; private set; } - public string EventName { get; private set; } + public string EventName { get; private set; } = default!; - public byte[] EventData { get; private set; } + public byte[] EventData { get; private set; } = default!; public DateTime CreationTime { get; private set; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs index 8e107d0d72..f9a9d21e6a 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs @@ -68,12 +68,12 @@ public class EfCoreAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonD return queryable.FirstAsync(predicate, cancellationToken); } - public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { return queryable.FirstOrDefaultAsync(cancellationToken); } - public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { return queryable.FirstOrDefaultAsync(predicate, cancellationToken); @@ -89,12 +89,12 @@ public class EfCoreAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonD return queryable.LastAsync(predicate, cancellationToken); } - public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { return queryable.LastOrDefaultAsync(cancellationToken); } - public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { return queryable.LastOrDefaultAsync(predicate, cancellationToken); @@ -110,12 +110,12 @@ public class EfCoreAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonD return queryable.SingleAsync(predicate, cancellationToken); } - public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { return queryable.SingleOrDefaultAsync(cancellationToken); } - public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { return queryable.SingleOrDefaultAsync(predicate, cancellationToken); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs index d21e4c43c5..cb97111c59 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs @@ -69,8 +69,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency return list; } - [CanBeNull] - protected virtual EntityChangeInfo CreateEntityChangeOrNull(EntityEntry entityEntry) + protected virtual EntityChangeInfo? CreateEntityChangeOrNull(EntityEntry entityEntry) { var entity = entityEntry.Entity; @@ -138,7 +137,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency } } - protected virtual string GetEntityId(object entityAsObj) + protected virtual string? GetEntityId(object entityAsObj) { if ((entityAsObj is IEntity entity)) { @@ -370,10 +369,10 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency // Add foreign key entityChange.PropertyChanges.Add(new EntityPropertyChangeInfo { - NewValue = JsonSerializer.Serialize(propertyEntry.CurrentValue), - OriginalValue = JsonSerializer.Serialize(propertyEntry.OriginalValue), + NewValue = JsonSerializer.Serialize(propertyEntry.CurrentValue!), + OriginalValue = JsonSerializer.Serialize(propertyEntry.OriginalValue!), PropertyName = property.Name, - PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName + PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName! }); } @@ -382,7 +381,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency if (propertyChange.OriginalValue == propertyChange.NewValue) { - var newValue = JsonSerializer.Serialize(propertyEntry.CurrentValue); + var newValue = JsonSerializer.Serialize(propertyEntry.CurrentValue!); if (newValue == propertyChange.NewValue) { // No change diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs index 014e893fdf..833163d223 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs @@ -60,17 +60,17 @@ public interface IEfCoreDbContext : IDisposable, IInfrastructure([NotNull] params object[] keyValues) where TEntity : class; + TEntity? Find([NotNull] params object[] keyValues) where TEntity : class; - ValueTask FindAsync([NotNull] Type entityType, [NotNull] object[] keyValues, CancellationToken cancellationToken); + ValueTask FindAsync([NotNull] Type entityType, [NotNull] object[] keyValues, CancellationToken cancellationToken); - ValueTask FindAsync([NotNull] object[] keyValues, CancellationToken cancellationToken) where TEntity : class; + ValueTask FindAsync([NotNull] object[] keyValues, CancellationToken cancellationToken) where TEntity : class; - ValueTask FindAsync([NotNull] params object[] keyValues) where TEntity : class; + ValueTask FindAsync([NotNull] params object[] keyValues) where TEntity : class; - ValueTask FindAsync([NotNull] Type entityType, [NotNull] params object[] keyValues); + ValueTask FindAsync([NotNull] Type entityType, [NotNull] params object[] keyValues); EntityEntry Remove([NotNull] TEntity entity) where TEntity : class; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs index d9fc7db914..a5dcbd65cc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreDatabaseMigrationEventHandlerBase.cs @@ -210,7 +210,7 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase : else { var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value); - if (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() || + if (!tenantConfiguration!.ConnectionStrings!.Default.IsNullOrWhiteSpace() || !tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace()) { //Migrating the tenant database (only if tenant has a separate database) @@ -301,7 +301,7 @@ public abstract class EfCoreDatabaseMigrationEventHandlerBase : return 0; } - return int.Parse(tryCountAsString); + return int.Parse(tryCountAsString!); } private static void SetEventTryCount(EtoBase eventData, int count) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderConfigurationOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderConfigurationOptions.cs index 4ea08edced..17b000eb45 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderConfigurationOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderConfigurationOptions.cs @@ -12,14 +12,14 @@ public class AbpModelBuilderConfigurationOptions _tablePrefix = value; } } - private string _tablePrefix; - [CanBeNull] - public string Schema { get; set; } + private string _tablePrefix = default!; + + public string? Schema { get; set; } public AbpModelBuilderConfigurationOptions( [NotNull] string tablePrefix = "", - [CanBeNull] string schema = null) + string? schema = null) { Check.NotNull(tablePrefix, nameof(tablePrefix)); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/QueryFilterExpressionHelper.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/QueryFilterExpressionHelper.cs index dfd5edf38f..1c60582ad0 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/QueryFilterExpressionHelper.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/QueryFilterExpressionHelper.cs @@ -29,7 +29,7 @@ public static class QueryFilterExpressionHelper _newValue = newValue; } - public override Expression Visit(Expression node) + public override Expression? Visit(Expression? node) { return node == _oldValue ? _newValue : base.Visit(node); } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/ExtraPropertyDictionaryValueComparer.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/ExtraPropertyDictionaryValueComparer.cs index 123ba2be46..dca9ee0fc0 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/ExtraPropertyDictionaryValueComparer.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/ExtraPropertyDictionaryValueComparer.cs @@ -9,7 +9,7 @@ public class ExtraPropertyDictionaryValueComparer : ValueComparer d1.SequenceEqual(d2), + (d1, d2) => d1!.SequenceEqual(d2!), d => d.Aggregate(0, (k, v) => HashCode.Combine(k, v.GetHashCode())), d => new ExtraPropertyDictionary(d)) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs index 17513d46a2..702890a0a7 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters; public class AbpDateTimeValueConverter : ValueConverter { - public AbpDateTimeValueConverter(IClock clock, [CanBeNull] ConverterMappingHints mappingHints = null) + public AbpDateTimeValueConverter(IClock clock, ConverterMappingHints? mappingHints = null) : base( x => clock.Normalize(x), x => clock.Normalize(x), mappingHints) @@ -17,7 +17,7 @@ public class AbpDateTimeValueConverter : ValueConverter public class AbpNullableDateTimeValueConverter : ValueConverter { - public AbpNullableDateTimeValueConverter(IClock clock, [CanBeNull] ConverterMappingHints mappingHints = null) + public AbpNullableDateTimeValueConverter(IClock clock, ConverterMappingHints? mappingHints = null) : base( x => x.HasValue ? clock.Normalize(x.Value) : x, x => x.HasValue ? clock.Normalize(x.Value) : x, mappingHints) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs index 5be0cf6911..80035c3252 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs @@ -29,6 +29,6 @@ public class AbpJsonValueConverter : ValueConverter(s, DeserializeOptions); + return JsonSerializer.Deserialize(s, DeserializeOptions)!; } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index 1aa9f48b07..640da7122c 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -19,9 +19,9 @@ public class ExtraPropertiesValueConverter : ValueConverter(extraProperties); + var copyDictionary = new Dictionary(extraProperties); if (entityType != null) { @@ -49,7 +49,7 @@ public class ExtraPropertiesValueConverter : ValueConverter dictionary, ObjectExtensionPropertyInfo property) { @@ -88,7 +88,7 @@ public class ExtraPropertiesValueConverter : ValueConverter entityTypeAndPropertyBuildAction) + Action? entityTypeAndPropertyBuildAction) { Check.NotNull(propertyExtension, nameof(propertyExtension)); @@ -56,8 +56,7 @@ public static class EfCoreObjectExtensionPropertyInfoExtensions return propertyExtension; } - [CanBeNull] - public static ObjectExtensionPropertyInfoEfCoreMappingOptions GetEfCoreMappingOrNull( + public static ObjectExtensionPropertyInfoEfCoreMappingOptions? GetEfCoreMappingOrNull( [NotNull] this ObjectExtensionPropertyInfo propertyExtension) { Check.NotNull(propertyExtension, nameof(propertyExtension)); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs index a63b23782a..8c23de2961 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs @@ -10,11 +10,9 @@ public class ObjectExtensionInfoEfCoreMappingOptions [NotNull] public ObjectExtensionInfo ObjectExtension { get; } - [CanBeNull] - public Action EntityTypeBuildAction { get; set; } + public Action? EntityTypeBuildAction { get; set; } - [CanBeNull] - public Action ModelBuildAction { get; set; } + public Action? ModelBuildAction { get; set; } public ObjectExtensionInfoEfCoreMappingOptions( [NotNull] ObjectExtensionInfo objectExtension, diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs index 3a9e67b1ea..49c6e89197 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs @@ -13,17 +13,15 @@ public class ObjectExtensionPropertyInfoEfCoreMappingOptions public ObjectExtensionInfo ObjectExtension => ExtensionProperty.ObjectExtension; [Obsolete("Use EntityTypeAndPropertyBuildAction property.")] - [CanBeNull] - public Action PropertyBuildAction { get; set; } + public Action? PropertyBuildAction { get; set; } - [CanBeNull] - public Action EntityTypeAndPropertyBuildAction { get; set; } + public Action? EntityTypeAndPropertyBuildAction { get; set; } [Obsolete("Use other constructors.")] public ObjectExtensionPropertyInfoEfCoreMappingOptions( [NotNull] ObjectExtensionPropertyInfo extensionProperty, - [CanBeNull] Action propertyBuildAction = null, - [CanBeNull] Action entityTypeAndPropertyBuildAction = null) + Action? propertyBuildAction = null, + Action? entityTypeAndPropertyBuildAction = null) { ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty)); @@ -39,7 +37,7 @@ public class ObjectExtensionPropertyInfoEfCoreMappingOptions public ObjectExtensionPropertyInfoEfCoreMappingOptions( [NotNull] ObjectExtensionPropertyInfo extensionProperty, - [CanBeNull] Action entityTypeAndPropertyBuildAction) + Action? entityTypeAndPropertyBuildAction) { ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty)); diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo.Abp.EventBus.Abstractions.csproj b/framework/src/Volo.Abp.EventBus.Abstractions/Volo.Abp.EventBus.Abstractions.csproj index b61d8315c1..d9a78b320b 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo.Abp.EventBus.Abstractions.csproj +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo.Abp.EventBus.Abstractions.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs index 42036d85ce..86d6009594 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs @@ -4,7 +4,7 @@ public class DistributedEventReceived { public DistributedEventSource Source { get; set; } - public string EventName { get; set; } + public string EventName { get; set; } = default!; - public object EventData { get; set; } + public object EventData { get; set; } = default!; } diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs index 990068e0cc..d94f927e35 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs @@ -4,7 +4,7 @@ public class DistributedEventSent { public DistributedEventSource Source { get; set; } - public string EventName { get; set; } + public string EventName { get; set; } = default!; - public object EventData { get; set; } + public object EventData { get; set; } = default!; } diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/InboxConfig.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/InboxConfig.cs index 94e0e55be9..35af3f2bc9 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/InboxConfig.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/InboxConfig.cs @@ -13,13 +13,13 @@ public class InboxConfig get => _databaseName; set => _databaseName = Check.NotNullOrWhiteSpace(value, nameof(DatabaseName)); } - [NotNull] private string _databaseName; + [NotNull] private string _databaseName = default!; - public Type ImplementationType { get; set; } + public Type ImplementationType { get; set; } = default!; - public Func EventSelector { get; set; } + public Func? EventSelector { get; set; } - public Func HandlerSelector { get; set; } + public Func? HandlerSelector { get; set; } /// /// Used to enable/disable processing incoming events. diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IncomingEventInfo.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IncomingEventInfo.cs index 372e4e3d77..ffd135845a 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IncomingEventInfo.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IncomingEventInfo.cs @@ -12,11 +12,11 @@ public class IncomingEventInfo : IHasExtraProperties public Guid Id { get; } - public string MessageId { get; } + public string MessageId { get; } = default!; - public string EventName { get; } + public string EventName { get; } = default!; - public byte[] EventData { get; } + public byte[] EventData { get; } = default!; public DateTime CreationTime { get; } @@ -47,7 +47,7 @@ public class IncomingEventInfo : IHasExtraProperties ExtraProperties[EventBusConsts.CorrelationIdHeaderName] = correlationId; } - public string GetCorrelationId() + public string? GetCorrelationId() { return ExtraProperties.GetOrDefault(EventBusConsts.CorrelationIdHeaderName)?.ToString(); } diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutboxConfig.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutboxConfig.cs index 0b327c0e3b..6e44b9c470 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutboxConfig.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutboxConfig.cs @@ -13,11 +13,11 @@ public class OutboxConfig get => _databaseName; set => _databaseName = Check.NotNullOrWhiteSpace(value, nameof(DatabaseName)); } - [NotNull] private string _databaseName; + [NotNull] private string _databaseName = default!; - public Type ImplementationType { get; set; } + public Type ImplementationType { get; set; } = default!; - public Func Selector { get; set; } + public Func? Selector { get; set; } /// /// Used to enable/disable sending events from outbox to the message broker. diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutgoingEventInfo.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutgoingEventInfo.cs index 299935741e..43e9c42bf8 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutgoingEventInfo.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/OutgoingEventInfo.cs @@ -12,9 +12,9 @@ public class OutgoingEventInfo : IHasExtraProperties public Guid Id { get; } - public string EventName { get; } + public string EventName { get; } = default!; - public byte[] EventData { get; } + public byte[] EventData { get; } = default!; public DateTime CreationTime { get; } @@ -43,7 +43,7 @@ public class OutgoingEventInfo : IHasExtraProperties ExtraProperties[EventBusConsts.CorrelationIdHeaderName] = correlationId; } - public string GetCorrelationId() + public string? GetCorrelationId() { return ExtraProperties.GetOrDefault(EventBusConsts.CorrelationIdHeaderName)?.ToString(); } diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/EventNameAttribute.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/EventNameAttribute.cs index 1f0b19dd3c..2ae85bd428 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/EventNameAttribute.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/EventNameAttribute.cs @@ -23,12 +23,12 @@ public class EventNameAttribute : Attribute, IEventNameProvider { Check.NotNull(eventType, nameof(eventType)); - return eventType - .GetCustomAttributes(true) - .OfType() - .FirstOrDefault() - ?.GetName(eventType) - ?? eventType.FullName; + return (eventType + .GetCustomAttributes(true) + .OfType() + .FirstOrDefault() + ?.GetName(eventType) + ?? eventType.FullName)!; } public string GetName(Type eventType) diff --git a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/GenericEventNameAttribute.cs b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/GenericEventNameAttribute.cs index 70493104c1..99c089be85 100644 --- a/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/GenericEventNameAttribute.cs +++ b/framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/GenericEventNameAttribute.cs @@ -5,9 +5,9 @@ namespace Volo.Abp.EventBus; [AttributeUsage(AttributeTargets.Class)] public class GenericEventNameAttribute : Attribute, IEventNameProvider { - public string Prefix { get; set; } + public string? Prefix { get; set; } - public string Postfix { get; set; } + public string? Postfix { get; set; } public virtual string GetName(Type eventType) { diff --git a/framework/src/Volo.Abp.EventBus.Azure/Volo.Abp.EventBus.Azure.csproj b/framework/src/Volo.Abp.EventBus.Azure/Volo.Abp.EventBus.Azure.csproj index 7cbaa944da..d467bd3796 100644 --- a/framework/src/Volo.Abp.EventBus.Azure/Volo.Abp.EventBus.Azure.csproj +++ b/framework/src/Volo.Abp.EventBus.Azure/Volo.Abp.EventBus.Azure.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.EventBus.Azure Volo.Abp.EventBus.Azure $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AbpAzureEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AbpAzureEventBusOptions.cs index 57fa4b7f48..a6c5aabf42 100644 --- a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AbpAzureEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AbpAzureEventBusOptions.cs @@ -2,11 +2,11 @@ namespace Volo.Abp.EventBus.Azure; public class AbpAzureEventBusOptions { - public string ConnectionName { get; set; } + public string? ConnectionName { get; set; } - public string SubscriberName { get; set; } + public string SubscriberName { get; set; } = default!; - public string TopicName { get; set; } + public string TopicName { get; set; } = default!; public bool IsServiceBusDisabled { get; set; } } diff --git a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs index d7ca68bee6..8e45a8887f 100644 --- a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs @@ -30,7 +30,7 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen protected IAzureServiceBusSerializer Serializer { get; } protected ConcurrentDictionary> HandlerFactories { get; } protected ConcurrentDictionary EventTypes { get; } - protected IAzureServiceBusMessageConsumer Consumer { get; private set; } + protected IAzureServiceBusMessageConsumer Consumer { get; private set; } = default!; public AzureDistributedEventBus( IServiceScopeFactory serviceScopeFactory, @@ -268,7 +268,7 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen protected virtual async Task PublishAsync( string eventName, byte[] body, - [CanBeNull] string correlationId, + string? correlationId, Guid? eventId) { var message = new ServiceBusMessage(body) diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj b/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj index 61f398fecf..47d0f09f64 100644 --- a/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventData.cs b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventData.cs index ee08586b8d..b4dfee64cd 100644 --- a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventData.cs +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventData.cs @@ -10,9 +10,9 @@ public class AbpDaprEventData public string JsonData { get; set; } - public string CorrelationId { get; set; } + public string? CorrelationId { get; set; } - public AbpDaprEventData(string pubSubName, string topic, string messageId, string jsonData, string correlationId) + public AbpDaprEventData(string pubSubName, string topic, string messageId, string jsonData, string? correlationId) { PubSubName = pubSubName; Topic = topic; diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs index 4912a58388..f4c3e6242f 100644 --- a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs @@ -114,7 +114,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend factories.RemoveAll( factory => factory is SingleInstanceHandlerFactory && - (factory as SingleInstanceHandlerFactory).HandlerInstance == handler + (factory as SingleInstanceHandlerFactory)!.HandlerInstance == handler ); }); } @@ -186,7 +186,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend } } - public virtual async Task TriggerHandlersAsync(Type eventType, object eventData, string messageId = null, string correlationId = null) + public virtual async Task TriggerHandlersAsync(Type eventType, object eventData, string? messageId = null, string? correlationId = null) { if (await AddToInboxAsync(messageId, EventNameAttribute.GetNameOrDefault(eventType), eventType, eventData, correlationId)) { @@ -245,15 +245,15 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend public Type GetEventType(string eventName) { - return EventTypes.GetOrDefault(eventName); + return EventTypes.GetOrDefault(eventName)!; } - protected virtual async Task PublishToDaprAsync(Type eventType, object eventData, Guid? messageId = null, string correlationId = null) + protected virtual async Task PublishToDaprAsync(Type eventType, object eventData, Guid? messageId = null, string? correlationId = null) { await PublishToDaprAsync(EventNameAttribute.GetNameOrDefault(eventType), eventData, messageId, correlationId); } - protected virtual async Task PublishToDaprAsync(string eventName, object eventData, Guid? messageId = null, string correlationId = null) + protected virtual async Task PublishToDaprAsync(string eventName, object eventData, Guid? messageId = null, string? correlationId = null) { var client = DaprClientFactory.Create(); var data = new AbpDaprEventData(DaprEventBusOptions.PubSubName, eventName, (messageId ?? GuidGenerator.Create()).ToString("N"), Serializer.SerializeToString(eventData), correlationId); diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo.Abp.EventBus.Kafka.csproj b/framework/src/Volo.Abp.EventBus.Kafka/Volo.Abp.EventBus.Kafka.csproj index 9a240aa49a..4d2ff65bd4 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo.Abp.EventBus.Kafka.csproj +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo.Abp.EventBus.Kafka.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/AbpKafkaEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/AbpKafkaEventBusOptions.cs index eb5f898e68..17dc9e3796 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/AbpKafkaEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/AbpKafkaEventBusOptions.cs @@ -3,9 +3,9 @@ public class AbpKafkaEventBusOptions { - public string ConnectionName { get; set; } + public string? ConnectionName { get; set; } - public string TopicName { get; set; } + public string TopicName { get; set; } = default!; - public string GroupId { get; set; } + public string GroupId { get; set; } = default!; } diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs index b49ffc07a9..a777ff7da2 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs @@ -29,7 +29,7 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen protected IProducerPool ProducerPool { get; } protected ConcurrentDictionary> HandlerFactories { get; } protected ConcurrentDictionary EventTypes { get; } - protected IKafkaMessageConsumer Consumer { get; private set; } + protected IKafkaMessageConsumer Consumer { get; private set; } = default!; public KafkaDistributedEventBus( IServiceScopeFactory serviceScopeFactory, diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/MessageExtensions.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/MessageExtensions.cs index 569e56a1dc..cb487ed00f 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/MessageExtensions.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/MessageExtensions.cs @@ -4,9 +4,9 @@ namespace Volo.Abp.EventBus.Kafka; public static class MessageExtensions { - public static string GetMessageId(this Message message) + public static string? GetMessageId(this Message message) { - string messageId = null; + string? messageId = null; if (message.Headers.TryGetLastBytes("messageId", out var messageIdBytes)) { @@ -16,9 +16,9 @@ public static class MessageExtensions return messageId; } - public static string GetCorrelationId(this Message message) + public static string? GetCorrelationId(this Message message) { - string correlationId = null; + string? correlationId = null; if (message.Headers.TryGetLastBytes(EventBusConsts.CorrelationIdHeaderName, out var correlationIdBytes)) { diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo.Abp.EventBus.RabbitMQ.csproj b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo.Abp.EventBus.RabbitMQ.csproj index 73c4d4a69a..b9d46a8a99 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo.Abp.EventBus.RabbitMQ.csproj +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo.Abp.EventBus.RabbitMQ.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.EventBus.RabbitMQ Volo.Abp.EventBus.RabbitMQ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs index bac9bdf0c9..a017d53d5d 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs @@ -6,13 +6,13 @@ public class AbpRabbitMqEventBusOptions { public const string DefaultExchangeType = RabbitMqConsts.ExchangeTypes.Direct; - public string ConnectionName { get; set; } + public string? ConnectionName { get; set; } - public string ClientName { get; set; } + public string ClientName { get; set; } = default!; - public string ExchangeName { get; set; } + public string ExchangeName { get; set; } = default!; - public string ExchangeType { get; set; } + public string? ExchangeType { get; set; } public ushort? PrefetchCount { get; set; } @@ -20,6 +20,6 @@ public class AbpRabbitMqEventBusOptions { return string.IsNullOrEmpty(ExchangeType) ? DefaultExchangeType - : ExchangeType; + : ExchangeType!; } } diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index e484fa792b..2c0bb7aab5 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -35,7 +35,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe protected ConcurrentDictionary> HandlerFactories { get; } protected ConcurrentDictionary EventTypes { get; } protected IRabbitMqMessageConsumerFactory MessageConsumerFactory { get; } - protected IRabbitMqMessageConsumer Consumer { get; private set; } + protected IRabbitMqMessageConsumer Consumer { get; private set; } = default!; private bool _exchangeCreated; @@ -175,7 +175,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe factories.RemoveAll( factory => factory is SingleInstanceHandlerFactory && - (factory as SingleInstanceHandlerFactory).HandlerInstance == handler + (factory as SingleInstanceHandlerFactory)!.HandlerInstance == handler ); }); } @@ -282,9 +282,9 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe public virtual Task PublishAsync( Type eventType, object eventData, - Dictionary headersArguments = null, + Dictionary? headersArguments = null, Guid? eventId = null, - [CanBeNull] string correlationId = null) + string? correlationId = null) { var eventName = EventNameAttribute.GetNameOrDefault(eventType); var body = Serializer.Serialize(eventData); @@ -295,9 +295,9 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe protected virtual Task PublishAsync( string eventName, byte[] body, - Dictionary headersArguments = null, + Dictionary? headersArguments = null, Guid? eventId = null, - [CanBeNull] string correlationId = null) + string? correlationId = null) { using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) { @@ -309,9 +309,9 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe IModel channel, string eventName, byte[] body, - Dictionary headersArguments = null, + Dictionary? headersArguments = null, Guid? eventId = null, - [CanBeNull] string correlationId = null) + string? correlationId = null) { EnsureExchangeExists(channel); @@ -366,7 +366,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe _exchangeCreated = true; } - private void SetEventMessageHeaders(IBasicProperties properties, Dictionary headersArguments) + private void SetEventMessageHeaders(IBasicProperties properties, Dictionary? headersArguments) { if (headersArguments == null) { diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj b/framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj index 9800674fab..f8c668dd8e 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.EventBus.Rebus Volo.Abp.EventBus.Rebus $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpRebusEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpRebusEventBusOptions.cs index 4c39b9bf1d..d128621396 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpRebusEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/AbpRebusEventBusOptions.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.EventBus.Rebus; public class AbpRebusEventBusOptions { [NotNull] - public string InputQueueName { get; set; } + public string InputQueueName { get; set; } = default!; [NotNull] public Action Configurer { @@ -20,7 +20,7 @@ public class AbpRebusEventBusOptions } private Action _configurer; - public Func Publish { get; set; } + public Func? Publish { get; set; } public AbpRebusEventBusOptions() { diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs index 560b13ba14..4b4dd3eef7 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs @@ -165,7 +165,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen var headers = new Dictionary(); if (CorrelationIdProvider.Get() != null) { - headers.Add(EventBusConsts.CorrelationIdHeaderName, CorrelationIdProvider.Get()); + headers.Add(EventBusConsts.CorrelationIdHeaderName, CorrelationIdProvider.Get()!); } await PublishAsync(eventType, eventData, headersArguments: headers); } @@ -174,7 +174,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen Type eventType, object eventData, Guid? eventId = null, - Dictionary headersArguments = null) + Dictionary? headersArguments = null) { if (AbpRebusEventBusOptions.Publish != null) { @@ -250,7 +250,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig) { - var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName); + var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName)!; var eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType); using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId())) @@ -265,7 +265,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen var headers = new Dictionary(); if (outgoingEvent.GetCorrelationId() != null) { - headers.Add(EventBusConsts.CorrelationIdHeaderName, outgoingEvent.GetCorrelationId()); + headers.Add(EventBusConsts.CorrelationIdHeaderName, outgoingEvent.GetCorrelationId()!); } await PublishAsync(eventType, eventData, eventId: outgoingEvent.Id, headersArguments: headers); diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventHandlerAdapter.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventHandlerAdapter.cs index 7f9343ecdf..037c6e3312 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventHandlerAdapter.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventHandlerAdapter.cs @@ -14,6 +14,6 @@ public class RebusDistributedEventHandlerAdapter : IHandleMessages netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.EventBus Volo.Abp.EventBus $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs index 670aa6ef23..17d497f883 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs @@ -133,7 +133,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB Serialize(eventData), Clock.Now ); - outgoingEventInfo.SetCorrelationId(CorrelationIdProvider.Get()); + outgoingEventInfo.SetCorrelationId(CorrelationIdProvider.Get()!); await eventOutbox.EnqueueAsync(outgoingEventInfo); return true; } @@ -148,11 +148,11 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB } protected async Task AddToInboxAsync( - string messageId, + string? messageId, string eventName, Type eventType, object eventData, - [CanBeNull] string correlationId) + string? correlationId) { if (AbpDistributedEventBusOptions.Inboxes.Count <= 0) { @@ -170,7 +170,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB if (!messageId.IsNullOrEmpty()) { - if (await eventInbox.ExistsByMessageIdAsync(messageId)) + if (await eventInbox.ExistsByMessageIdAsync(messageId!)) { continue; } @@ -178,12 +178,12 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB var incomingEventInfo = new IncomingEventInfo( GuidGenerator.Create(), - messageId, + messageId!, eventName, Serialize(eventData), Clock.Now ); - incomingEventInfo.SetCorrelationId(correlationId); + incomingEventInfo.SetCorrelationId(correlationId!); await eventInbox.EnqueueAsync(incomingEventInfo); } } @@ -206,7 +206,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB await TriggerHandlersAsync(eventType, eventData); } - protected virtual async Task TriggerHandlersFromInboxAsync(Type eventType, object eventData, List exceptions, InboxConfig inboxConfig = null) + protected virtual async Task TriggerHandlersFromInboxAsync(Type eventType, object eventData, List exceptions, InboxConfig? inboxConfig = null) { await TriggerDistributedEventReceivedAsync(new DistributedEventReceived { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/InboxProcessor.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/InboxProcessor.cs index 14e80bd9c6..e2c0a3c0c6 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/InboxProcessor.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/InboxProcessor.cs @@ -21,13 +21,13 @@ public class InboxProcessor : IInboxProcessor, ITransientDependency protected IAbpDistributedLock DistributedLock { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IClock Clock { get; } - protected IEventInbox Inbox { get; private set; } - protected InboxConfig InboxConfig { get; private set; } + protected IEventInbox Inbox { get; private set; } = default!; + protected InboxConfig InboxConfig { get; private set; } = default!; protected AbpEventBusBoxesOptions EventBusBoxesOptions { get; } protected DateTime? LastCleanTime { get; set; } - protected string DistributedLockName { get; private set; } + protected string DistributedLockName { get; private set; } = default!; public ILogger Logger { get; set; } protected CancellationTokenSource StoppingTokenSource { get; } protected CancellationToken StoppingToken { get; } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/OutboxSender.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/OutboxSender.cs index 5f34761b17..99ee06ca10 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/OutboxSender.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/OutboxSender.cs @@ -19,10 +19,10 @@ public class OutboxSender : IOutboxSender, ITransientDependency protected AbpAsyncTimer Timer { get; } protected IDistributedEventBus DistributedEventBus { get; } protected IAbpDistributedLock DistributedLock { get; } - protected IEventOutbox Outbox { get; private set; } - protected OutboxConfig OutboxConfig { get; private set; } + protected IEventOutbox Outbox { get; private set; } = default!; + protected OutboxConfig OutboxConfig { get; private set; } = default!; protected AbpEventBusBoxesOptions EventBusBoxesOptions { get; } - protected string DistributedLockName { get; private set; } + protected string DistributedLockName { get; private set; } = default!; public ILogger Logger { get; set; } protected CancellationTokenSource StoppingTokenSource { get; } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 516a0008d7..ef5c5cdabc 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -131,7 +131,7 @@ public abstract class EventBusBase : IEventBus } } - protected virtual async Task TriggerHandlersAsync(Type eventType, object eventData, List exceptions, InboxConfig inboxConfig = null) + protected virtual async Task TriggerHandlersAsync(Type eventType, object eventData, List exceptions, InboxConfig? inboxConfig = null) { await new SynchronizationContextRemover(); @@ -154,7 +154,7 @@ public abstract class EventBusBase : IEventBus { var baseEventType = eventType.GetGenericTypeDefinition().MakeGenericType(baseArg); var constructorArgs = ((IEventDataWithInheritableGenericArgument)eventData).GetConstructorArgs(); - var baseEventData = Activator.CreateInstance(baseEventType, constructorArgs); + var baseEventData = Activator.CreateInstance(baseEventType, constructorArgs)!; await PublishToEventBusAsync(baseEventType, baseEventData); } } @@ -197,7 +197,7 @@ public abstract class EventBusBase : IEventBus protected abstract IEnumerable GetHandlerFactories(Type eventType); protected virtual async Task TriggerHandlerAsync(IEventHandlerFactory asyncHandlerFactory, Type eventType, - object eventData, List exceptions, InboxConfig inboxConfig = null) + object eventData, List exceptions, InboxConfig? inboxConfig = null) { using (var eventHandlerWrapper = asyncHandlerFactory.GetHandler()) { @@ -218,7 +218,7 @@ public abstract class EventBusBase : IEventBus } catch (TargetInvocationException ex) { - exceptions.Add(ex.InnerException); + exceptions.Add(ex.InnerException!); } catch (Exception ex) { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs index 8a27ab84c7..eea4e662c8 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs @@ -6,9 +6,9 @@ public class EventHandlerDisposeWrapper : IEventHandlerDisposeWrapper { public IEventHandler EventHandler { get; } - private readonly Action _disposeAction; + private readonly Action? _disposeAction; - public EventHandlerDisposeWrapper(IEventHandler eventHandler, Action disposeAction = null) + public EventHandlerDisposeWrapper(IEventHandler eventHandler, Action? disposeAction = null) { _disposeAction = disposeAction; EventHandler = eventHandler; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs index 5c7517cfe1..9ee7c6cceb 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs @@ -23,12 +23,12 @@ public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency if (typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) { - item.Local = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(LocalEventHandlerMethodExecutor<>).MakeGenericType(eventType)); + item.Local = (IEventHandlerMethodExecutor?)Activator.CreateInstance(typeof(LocalEventHandlerMethodExecutor<>).MakeGenericType(eventType)); } if (typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) { - item.Distributed = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(DistributedEventHandlerMethodExecutor<>).MakeGenericType(eventType)); + item.Distributed = (IEventHandlerMethodExecutor?)Activator.CreateInstance(typeof(DistributedEventHandlerMethodExecutor<>).MakeGenericType(eventType)); } return item; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs index 0ec617afca..e579c547de 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs @@ -2,7 +2,7 @@ public class EventHandlerInvokerCacheItem { - public IEventHandlerMethodExecutor Local { get; set; } + public IEventHandlerMethodExecutor? Local { get; set; } - public IEventHandlerMethodExecutor Distributed { get; set; } + public IEventHandlerMethodExecutor? Distributed { get; set; } } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index d73b2f8de9..c24627cdc5 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -105,7 +105,7 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency factories.RemoveAll( factory => factory is SingleInstanceHandlerFactory && - (factory as SingleInstanceHandlerFactory).HandlerInstance == handler + ((factory as SingleInstanceHandlerFactory)!).HandlerInstance == handler ); }); } @@ -177,7 +177,7 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency } // Internal for unit testing - internal Func OnEventHandleInvoking { get; set; } + internal Func? OnEventHandleInvoking { get; set; } // Internal for unit testing protected async override Task InvokeEventHandlerAsync(IEventHandler eventHandler, object eventData, Type eventType) @@ -191,7 +191,7 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency } // Internal for unit testing - internal Func OnPublishing { get; set; } + internal Func? OnPublishing { get; set; } // For unit testing public async override Task PublishAsync( diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs index d84999cb24..75d9e26060 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs @@ -64,6 +64,6 @@ public class TransientEventHandlerFactory : IEventHandlerFactory protected virtual IEventHandler CreateHandler() { - return (IEventHandler)Activator.CreateInstance(HandlerType); + return (IEventHandler)Activator.CreateInstance(HandlerType)!; } } diff --git a/framework/src/Volo.Abp.Http.Abstractions/Volo.Abp.Http.Abstractions.csproj b/framework/src/Volo.Abp.Http.Abstractions/Volo.Abp.Http.Abstractions.csproj index 332c803147..adbc783c15 100644 --- a/framework/src/Volo.Abp.Http.Abstractions/Volo.Abp.Http.Abstractions.csproj +++ b/framework/src/Volo.Abp.Http.Abstractions/Volo.Abp.Http.Abstractions.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Http.Abstractions Volo.Abp.Http.Abstractions $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Abstractions/Volo/Abp/Http/ClientProxyExceptionEventData.cs b/framework/src/Volo.Abp.Http.Abstractions/Volo/Abp/Http/ClientProxyExceptionEventData.cs index 1bc17c7b65..029556c00e 100644 --- a/framework/src/Volo.Abp.Http.Abstractions/Volo/Abp/Http/ClientProxyExceptionEventData.cs +++ b/framework/src/Volo.Abp.Http.Abstractions/Volo/Abp/Http/ClientProxyExceptionEventData.cs @@ -4,5 +4,5 @@ public class ClientProxyExceptionEventData { public int? StatusCode { get; set; } - public string ReasonPhrase { get; set; } + public string? ReasonPhrase { get; set; } } diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj b/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj index 0d22e68b97..1fd0b7b07b 100644 --- a/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj +++ b/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs index 9ebfb5665d..4a17c3b67a 100644 --- a/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs +++ b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs @@ -12,7 +12,7 @@ public class AbpInvocationHandler : InvocationHandler, ITransientDependency { if (!daprOptions.Value.HttpEndpoint.IsNullOrWhiteSpace()) { - DaprEndpoint = daprOptions.Value.HttpEndpoint; + DaprEndpoint = daprOptions.Value.HttpEndpoint!; } } } diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo.Abp.Http.Client.IdentityModel.MauiBlazor.csproj b/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo.Abp.Http.Client.IdentityModel.MauiBlazor.csproj index 671fd3db2d..4a92cc975d 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo.Abp.Http.Client.IdentityModel.MauiBlazor.csproj +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo.Abp.Http.Client.IdentityModel.MauiBlazor.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.Http.Client.IdentityModel.MauiBlazor $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo/Abp/Http/Client/IdentityModel/MauiBlazor/MauiBlazorAbpAccessTokenProvider.cs b/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo/Abp/Http/Client/IdentityModel/MauiBlazor/MauiBlazorAbpAccessTokenProvider.cs index 8afbcbafed..3f923aa9bb 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo/Abp/Http/Client/IdentityModel/MauiBlazor/MauiBlazorAbpAccessTokenProvider.cs +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.MauiBlazor/Volo/Abp/Http/Client/IdentityModel/MauiBlazor/MauiBlazorAbpAccessTokenProvider.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.Http.Client.IdentityModel.MauiBlazor; [Dependency(ReplaceServices = true)] public class MauiBlazorAbpAccessTokenProvider : IAbpAccessTokenProvider, ITransientDependency { - public virtual Task GetTokenAsync() + public virtual Task GetTokenAsync() { return Task.FromResult(null as string); } diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj index 4fc1525e59..05d1a14ef8 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.Http.Client.IdentityModel.Web Volo.Abp.Http.Client.IdentityModel.Web $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo/Abp/Http/Client/IdentityModel/Web/HttpContextAbpAccessTokenProvider.cs b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo/Abp/Http/Client/IdentityModel/Web/HttpContextAbpAccessTokenProvider.cs index 97d88bd3b0..5044513438 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo/Abp/Http/Client/IdentityModel/Web/HttpContextAbpAccessTokenProvider.cs +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo/Abp/Http/Client/IdentityModel/Web/HttpContextAbpAccessTokenProvider.cs @@ -16,7 +16,7 @@ public class HttpContextAbpAccessTokenProvider : IAbpAccessTokenProvider, ITrans HttpContextAccessor = httpContextAccessor; } - public virtual async Task GetTokenAsync() + public virtual async Task GetTokenAsync() { var httpContext = HttpContextAccessor?.HttpContext; if (httpContext == null) diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj b/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj index e98f5d92ff..42d60909bc 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.Http.Client.IdentityModel.WebAssembly Volo.Abp.Http.Client.IdentityModel.WebAssembly $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo/Abp/Http/Client/IdentityModel/WebAssembly/WebAssemblyAbpAccessTokenProvider.cs b/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo/Abp/Http/Client/IdentityModel/WebAssembly/WebAssemblyAbpAccessTokenProvider.cs index d0a68cdb7c..137787820b 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo/Abp/Http/Client/IdentityModel/WebAssembly/WebAssemblyAbpAccessTokenProvider.cs +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly/Volo/Abp/Http/Client/IdentityModel/WebAssembly/WebAssemblyAbpAccessTokenProvider.cs @@ -8,14 +8,14 @@ namespace Volo.Abp.Http.Client.IdentityModel.WebAssembly; [Dependency(ReplaceServices = true)] public class WebAssemblyAbpAccessTokenProvider : IAbpAccessTokenProvider, ITransientDependency { - protected IAccessTokenProvider AccessTokenProvider { get; } + protected IAccessTokenProvider? AccessTokenProvider { get; } public WebAssemblyAbpAccessTokenProvider(IAccessTokenProvider accessTokenProvider) { AccessTokenProvider = accessTokenProvider; } - public virtual async Task GetTokenAsync() + public virtual async Task GetTokenAsync() { if (AccessTokenProvider == null) { diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo.Abp.Http.Client.IdentityModel.csproj b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo.Abp.Http.Client.IdentityModel.csproj index 083e987d49..3e791a1e69 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo.Abp.Http.Client.IdentityModel.csproj +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo.Abp.Http.Client.IdentityModel.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Http.Client.IdentityModel Volo.Abp.Http.Client.IdentityModel $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs index 417875619b..58c4b71078 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs @@ -8,8 +8,7 @@ public static class RemoteServiceConfigurationExtensions public const string IdentityClientName = "IdentityClient"; public const string UseCurrentAccessTokenName = "UseCurrentAccessToken"; - [CanBeNull] - public static string GetIdentityClient([NotNull] this RemoteServiceConfiguration configuration) + public static string? GetIdentityClient([NotNull] this RemoteServiceConfiguration configuration) { Check.NotNullOrEmpty(configuration, nameof(configuration)); diff --git a/framework/src/Volo.Abp.Http.Client.Web/Volo.Abp.Http.Client.Web.csproj b/framework/src/Volo.Abp.Http.Client.Web/Volo.Abp.Http.Client.Web.csproj index 68bbbd1157..63da778ecd 100644 --- a/framework/src/Volo.Abp.Http.Client.Web/Volo.Abp.Http.Client.Web.csproj +++ b/framework/src/Volo.Abp.Http.Client.Web/Volo.Abp.Http.Client.Web.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.Http.Client.Web Volo.Abp.Http.Client.Web $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs index 49080939c2..a7a2aad343 100644 --- a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs +++ b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs @@ -69,7 +69,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention if (controllerApiDescription != null && !controllerApiDescription.ControllerGroupName.IsNullOrWhiteSpace()) { - controller.ControllerName = controllerApiDescription.ControllerGroupName; + controller.ControllerName = controllerApiDescription.ControllerGroupName!; } ConfigureClientProxySelector(controller); @@ -115,7 +115,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention { var selector = controller.Selectors.FirstOrDefault(); selector?.EndpointMetadata.Add(new AreaAttribute(moduleApiDescription.RootPath)); - controller.RouteValues.Add(new KeyValuePair("area", moduleApiDescription.RootPath)); + controller.RouteValues.Add(new KeyValuePair("area", moduleApiDescription.RootPath)); } var controllerType = controller.ControllerType.AsType(); @@ -163,7 +163,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention var abpServiceSelectorModel = new SelectorModel { AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(template: actionApiDescriptionModel.Url)), - ActionConstraints = { new HttpMethodActionConstraint(new[] { actionApiDescriptionModel.HttpMethod }) } + ActionConstraints = { new HttpMethodActionConstraint(new[] { actionApiDescriptionModel.HttpMethod! }) } }; action.Selectors.Add(abpServiceSelectorModel); @@ -190,7 +190,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention if (!selector.ActionConstraints.OfType().Any()) { - selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); + selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod! })); } } } @@ -226,7 +226,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention } } - protected virtual ModuleApiDescriptionModel FindModuleApiDescriptionModel(ControllerModel controller) + protected virtual ModuleApiDescriptionModel? FindModuleApiDescriptionModel(ControllerModel controller) { var appServiceType = FindAppServiceInterfaceType(controller); if (appServiceType == null) @@ -246,7 +246,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention return null; } - protected virtual ControllerApiDescriptionModel FindControllerApiDescriptionModel(ControllerModel controller) + protected virtual ControllerApiDescriptionModel? FindControllerApiDescriptionModel(ControllerModel controller) { var appServiceType = FindAppServiceInterfaceType(controller); if (appServiceType == null) @@ -266,7 +266,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention return null; } - protected virtual ActionApiDescriptionModel FindActionApiDescriptionModel(ControllerModel controller, ActionModel action) + protected virtual ActionApiDescriptionModel? FindActionApiDescriptionModel(ControllerModel controller, ActionModel action) { var appServiceType = FindAppServiceInterfaceType(controller); if (appServiceType == null) @@ -285,7 +285,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention return null; } - if (actionApiDescriptionModel.ImplementFrom.StartsWith("Volo.Abp.Application.Services")) + if (actionApiDescriptionModel.ImplementFrom!.StartsWith("Volo.Abp.Application.Services")) { return actionApiDescriptionModel; } @@ -298,7 +298,7 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention return null; } - protected virtual Type FindAppServiceInterfaceType(ControllerModel controller) + protected virtual Type? FindAppServiceInterfaceType(ControllerModel controller) { return controller.ControllerType.GetInterfaces() .FirstOrDefault(type => !type.IsGenericType && diff --git a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs index 3f71924f9d..ab8d5974a8 100644 --- a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs +++ b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs @@ -191,7 +191,7 @@ public static class ServiceCollectionHttpClientProxyExtensions return Activator.CreateInstance( typeof(HttpClientProxy<>).MakeGenericType(type), service - ); + )!; }); return services; diff --git a/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj b/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj index 0b4e3ad76f..0b05d8b1c7 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj +++ b/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Http.Client Volo.Abp.Http.Client $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/IAbpAccessTokenProvider.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/IAbpAccessTokenProvider.cs index a4e9e650e3..ceadc832ec 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/IAbpAccessTokenProvider.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/IAbpAccessTokenProvider.cs @@ -4,5 +4,5 @@ namespace Volo.Abp.Http.Client.Authentication; public interface IAbpAccessTokenProvider { - Task GetTokenAsync(); + Task GetTokenAsync(); } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/NullAbpAccessTokenProvider.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/NullAbpAccessTokenProvider.cs index 6bd7e6344b..47ae349bf0 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/NullAbpAccessTokenProvider.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Authentication/NullAbpAccessTokenProvider.cs @@ -5,7 +5,7 @@ namespace Volo.Abp.Http.Client.Authentication; public class NullAbpAccessTokenProvider : IAbpAccessTokenProvider, ITransientDependency { - public Task GetTokenAsync() + public Task GetTokenAsync() { return Task.FromResult(null as string); } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs index 9c54fe840e..e8da52f3b1 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs @@ -1,8 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; using Volo.Abp.Json; @@ -15,7 +17,7 @@ public class ClientProxyApiDescriptionFinder : IClientProxyApiDescriptionFinder, protected IVirtualFileProvider VirtualFileProvider { get; } protected IJsonSerializer JsonSerializer { get; } protected Dictionary ActionApiDescriptionModels { get; } - protected ApplicationApiDescriptionModel ApplicationApiDescriptionModel { get; set; } + protected ApplicationApiDescriptionModel ApplicationApiDescriptionModel { get; set; } = default!; public ClientProxyApiDescriptionFinder( IVirtualFileProvider virtualFileProvider, @@ -28,7 +30,7 @@ public class ClientProxyApiDescriptionFinder : IClientProxyApiDescriptionFinder, Initialize(); } - public ActionApiDescriptionModel FindAction(string methodName) + public ActionApiDescriptionModel? FindAction(string methodName) { return ActionApiDescriptionModels.ContainsKey(methodName) ? ActionApiDescriptionModels[methodName] : null; } @@ -92,15 +94,35 @@ public class ClientProxyApiDescriptionFinder : IClientProxyApiDescriptionFinder, { if (directoryContent.IsDirectory) { - GetGenerateProxyFileInfos(fileInfoList, directoryContent.PhysicalPath); + GetGenerateProxyFileInfos(fileInfoList, GetDirectoryContentPath(path, directoryContent)); } else { if (directoryContent.Name.EndsWith("generate-proxy.json")) { - fileInfoList.Add(VirtualFileProvider.GetFileInfo(directoryContent.GetVirtualOrPhysicalPathOrNull())); + fileInfoList.Add(VirtualFileProvider.GetFileInfo(GetProxyFileInfoPath(path, directoryContent))); } } } } + + private string GetDirectoryContentPath(string rootPath, IFileInfo fileInfo) + { + if (fileInfo is PhysicalDirectoryInfo physicalDirectoryInfo) + { + return rootPath + physicalDirectoryInfo.Name.EnsureStartsWith('/'); + } + + return fileInfo.PhysicalPath!; + } + + private string GetProxyFileInfoPath(string rootPath, IFileInfo fileInfo) + { + if (fileInfo is PhysicalFileInfo physicalFileInfo) + { + return rootPath + physicalFileInfo.Name.EnsureStartsWith('/'); + } + + return fileInfo.GetVirtualOrPhysicalPathOrNull()!; + } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs index 5c1d893bfd..8dee0fcc3e 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Http.Client.ClientProxying; public class ClientProxyBase : ITransientDependency { - public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; protected IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder => LazyServiceProvider.LazyGetRequiredService(); protected ICancellationTokenProvider CancellationTokenProvider => LazyServiceProvider.LazyGetRequiredService(); @@ -42,17 +42,17 @@ public class ClientProxyBase : ITransientDependency protected ICurrentApiVersionInfo CurrentApiVersionInfo => LazyServiceProvider.LazyGetRequiredService(); protected ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService(); - protected virtual async Task RequestAsync(string methodName, ClientProxyRequestTypeValue arguments = null) + protected virtual async Task RequestAsync(string methodName, ClientProxyRequestTypeValue? arguments = null) { await RequestAsync(BuildHttpProxyClientProxyContext(methodName, arguments)); } - protected virtual async Task RequestAsync(string methodName, ClientProxyRequestTypeValue arguments = null) + protected virtual async Task RequestAsync(string methodName, ClientProxyRequestTypeValue? arguments = null) { return await RequestAsync(BuildHttpProxyClientProxyContext(methodName, arguments)); } - protected virtual ClientProxyRequestContext BuildHttpProxyClientProxyContext(string methodName, ClientProxyRequestTypeValue arguments = null) + protected virtual ClientProxyRequestContext BuildHttpProxyClientProxyContext(string methodName, ClientProxyRequestTypeValue? arguments = null) { if (arguments == null) { @@ -67,7 +67,7 @@ public class ClientProxyBase : ITransientDependency } var actionArguments = action.Parameters.GroupBy(x => x.NameOnMethod).ToList(); - if (action.SupportedVersions.Any()) + if (action.SupportedVersions != null && action.SupportedVersions.Any()) { //TODO: make names configurable actionArguments.RemoveAll(x => x.Key == "api-version" || x.Key == "apiVersion"); @@ -107,7 +107,7 @@ public class ClientProxyBase : ITransientDependency if (stringContent.IsNullOrWhiteSpace()) { - return default; + return default!; } return JsonSerializer.Deserialize(stringContent); @@ -177,7 +177,7 @@ public class ClientProxyBase : ITransientDependency var versionParam = requestContext.Action.Parameters.FirstOrDefault(p => p.Name == "apiVersion" && p.BindingSourceId == ParameterBindingSources.Path) ?? requestContext.Action.Parameters.FirstOrDefault(p => p.Name == "api-version" && p.BindingSourceId == ParameterBindingSources.Query); - return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion); + return new ApiVersionInfo(versionParam?.BindingSourceId!, apiVersion); } protected virtual async Task GetUrlWithParametersAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion) @@ -185,7 +185,7 @@ public class ClientProxyBase : ITransientDependency return await ClientProxyUrlBuilder.GenerateUrlWithParametersAsync(requestContext.Action, requestContext.Arguments, apiVersion); } - protected virtual async Task GetHttpContentAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion) + protected virtual async Task GetHttpContentAsync(ClientProxyRequestContext requestContext, ApiVersionInfo apiVersion) { return await ClientProxyRequestPayloadBuilder.BuildContentAsync(requestContext.Action, requestContext.Arguments, JsonSerializer, apiVersion); } @@ -199,15 +199,15 @@ public class ClientProxyBase : ITransientDependency return configuredVersion ?? "1.0"; } - if (requestContext.Action.SupportedVersions.Contains(configuredVersion)) + if (requestContext.Action.SupportedVersions!.Contains(configuredVersion!)) { - return configuredVersion; + return configuredVersion!; } return requestContext.Action.SupportedVersions.Last(); //TODO: Ensure to get the latest version! } - protected virtual async Task GetConfiguredApiVersionAsync(ClientProxyRequestContext requestContext) + protected virtual async Task GetConfiguredApiVersionAsync(ClientProxyRequestContext requestContext) { var clientConfig = ClientOptions.Value.HttpClientProxies.GetOrDefault(requestContext.ServiceType) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {requestContext.ServiceType.FullName}."); @@ -220,8 +220,8 @@ public class ClientProxyBase : ITransientDependency { await LocalEventBus.PublishAsync(new ClientProxyExceptionEventData() { - StatusCode = (int?)response?.StatusCode, - ReasonPhrase = response?.ReasonPhrase + StatusCode = (int?)response.StatusCode, + ReasonPhrase = response.ReasonPhrase }); if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat)) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs index abbbb8b6f1..d7755a1ac9 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyRequestPayloadBuilder.cs @@ -40,8 +40,7 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency HttpClientProxyingOptions = httpClientProxyingOptions.Value; } - [CanBeNull] - public virtual async Task BuildContentAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, IJsonSerializer jsonSerializer, ApiVersionInfo apiVersion) + public virtual async Task BuildContentAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, IJsonSerializer jsonSerializer, ApiVersionInfo apiVersion) { var body = await GenerateBodyAsync(action, methodArguments, jsonSerializer); if (body != null) @@ -54,7 +53,7 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency return body; } - protected virtual Task GenerateBodyAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, IJsonSerializer jsonSerializer) + protected virtual Task GenerateBodyAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments, IJsonSerializer jsonSerializer) { var parameters = action .Parameters @@ -63,7 +62,7 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency if (parameters.Length <= 0) { - return Task.FromResult(null); + return Task.FromResult(null); } if (parameters.Length > 1) @@ -76,13 +75,13 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameters[0]); if (value == null) { - return Task.FromResult(null); + return Task.FromResult(null); } - return Task.FromResult(new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json)); + return Task.FromResult(new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json)); } - protected virtual async Task GenerateFormPostDataAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments) + protected virtual async Task GenerateFormPostDataAsync(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments) { var parameters = action .Parameters @@ -108,7 +107,7 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency { using (var scope = ServiceScopeFactory.CreateScope()) { - var formDataContents = await (Task>>)CallObjectToFormDataAsyncMethod + var formDataContents = await (Task>?>)CallObjectToFormDataAsyncMethod .MakeGenericMethod(value.GetType()) .Invoke(this, new object[] { @@ -116,7 +115,7 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency action, parameter, value - }); + })!; if (formDataContents != null) { @@ -158,12 +157,12 @@ public class ClientProxyRequestPayloadBuilder : ITransientDependency { foreach (var item in (IEnumerable) value) { - formData.Add(new StringContent(item.ToString(), Encoding.UTF8), parameter.Name); + formData.Add(new StringContent(item.ToString()!, Encoding.UTF8), parameter.Name); } } else { - formData.Add(new StringContent(value.ToString(), Encoding.UTF8), parameter.Name); + formData.Add(new StringContent(value.ToString()!, Encoding.UTF8), parameter.Name); } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs index 63ddd75510..65703dc56b 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyUrlBuilder.cs @@ -100,15 +100,15 @@ public class ClientProxyUrlBuilder : ITransientDependency { using (var scope = ServiceScopeFactory.CreateScope()) { - var path = await (Task)CallObjectToPathAsyncMethod + var path = await (Task)CallObjectToPathAsyncMethod .MakeGenericMethod(value.GetType()) - .Invoke(this, new object[] + .Invoke(this, new object?[] { scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.PathConverts[value.GetType()]), action, pathParameter, value - }); + })!; if (path != null) { @@ -143,7 +143,7 @@ public class ClientProxyUrlBuilder : ITransientDependency { using (var scope = ServiceScopeFactory.CreateScope()) { - var queryString = await (Task)CallObjectToQueryStringAsyncMethod + var queryString = await (Task)CallObjectToQueryStringAsyncMethod .MakeGenericMethod(value.GetType()) .Invoke(this, new object[] { @@ -151,7 +151,7 @@ public class ClientProxyUrlBuilder : ITransientDependency action, queryStringParameter, value - }); + })!; if (queryString != null) { @@ -218,11 +218,11 @@ public class ClientProxyUrlBuilder : ITransientDependency return true; } - protected virtual Task ConvertValueToStringAsync([CanBeNull] object value) + protected virtual Task ConvertValueToStringAsync(object? value) { if (value is DateTime dateTimeValue) { - return Task.FromResult(dateTimeValue.ToUniversalTime().ToString("O")); + return Task.FromResult(dateTimeValue.ToUniversalTime().ToString("O"))!; } return Task.FromResult(value?.ToString()); diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/CurrentApiVersionInfo.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/CurrentApiVersionInfo.cs index f56e9e893a..7c0bac4c81 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/CurrentApiVersionInfo.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/CurrentApiVersionInfo.cs @@ -6,11 +6,11 @@ namespace Volo.Abp.Http.Client.ClientProxying; public class CurrentApiVersionInfo : ICurrentApiVersionInfo, ISingletonDependency { - public ApiVersionInfo ApiVersionInfo => _currentApiVersionInfo.Value; + public ApiVersionInfo? ApiVersionInfo => _currentApiVersionInfo.Value; - private readonly AsyncLocal _currentApiVersionInfo = new AsyncLocal(); + private readonly AsyncLocal _currentApiVersionInfo = new AsyncLocal(); - public virtual IDisposable Change(ApiVersionInfo apiVersionInfo) + public virtual IDisposable Change(ApiVersionInfo? apiVersionInfo) { var parent = ApiVersionInfo; _currentApiVersionInfo.Value = apiVersionInfo; diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs index baf1d6facf..4394b92bcc 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Http.Client.ClientProxying; public interface IClientProxyApiDescriptionFinder { - ActionApiDescriptionModel FindAction(string methodName); + ActionApiDescriptionModel? FindAction(string methodName); ApplicationApiDescriptionModel GetApiDescription(); } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ICurrentApiVersionInfo.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ICurrentApiVersionInfo.cs index 9a8fe264bf..e5ac53fafe 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ICurrentApiVersionInfo.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ICurrentApiVersionInfo.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Http.Client.ClientProxying; public interface ICurrentApiVersionInfo { - ApiVersionInfo ApiVersionInfo { get; } + ApiVersionInfo? ApiVersionInfo { get; } - IDisposable Change(ApiVersionInfo apiVersionInfo); + IDisposable Change(ApiVersionInfo? apiVersionInfo); } 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 f01ada7127..44f005add9 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 @@ -118,7 +118,7 @@ public class ApiDescriptionFinder : IApiDescriptionFinder, ITransientDependency var content = await response.Content.ReadAsStringAsync(); - var result = JsonSerializer.Deserialize(content, DeserializeOptions); + var result = JsonSerializer.Deserialize(content, DeserializeOptions)!; return result; } 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 9c30c84496..0f5a9e3642 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 @@ -66,7 +66,7 @@ public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientD var returnType = invocation.Method.ReturnType.GenericTypeArguments[0]; var result = (Task)CallRequestAsyncMethod .MakeGenericMethod(returnType) - .Invoke(this, new object[] { context }); + .Invoke(this, new object[] { context })!; invocation.ReturnValue = await GetResultAsync(result, returnType); } @@ -99,6 +99,6 @@ public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientD .MakeGenericType(resultType) .GetProperty(nameof(Task.Result), BindingFlags.Instance | BindingFlags.Public); Check.NotNull(resultProperty, nameof(resultProperty)); - return resultProperty.GetValue(task); + return resultProperty!.GetValue(task)!; } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs index d5d5c4d971..f9fc79b81f 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/Proxying/HttpActionParameterHelper.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.Http.Client.Proxying; internal static class HttpActionParameterHelper { - public static object FindParameterValue(IReadOnlyDictionary methodArguments, ParameterApiDescriptionModel apiParameter) + public static object? FindParameterValue(IReadOnlyDictionary methodArguments, ParameterApiDescriptionModel apiParameter) { var value = methodArguments.GetOrDefault(apiParameter.NameOnMethod); if (value == null) diff --git a/framework/src/Volo.Abp.Http/Volo.Abp.Http.csproj b/framework/src/Volo.Abp.Http/Volo.Abp.Http.csproj index 3b029e3b9d..11cdaffe09 100644 --- a/framework/src/Volo.Abp.Http/Volo.Abp.Http.csproj +++ b/framework/src/Volo.Abp.Http/Volo.Abp.Http.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Http Volo.Abp.Http $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs index 603b6797c3..78ee75e901 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs @@ -43,12 +43,12 @@ public static class HttpMethodHelper return methodName; } - return methodName.RemovePreFix(prefixes); + return methodName.RemovePreFix(prefixes!); } - public static HttpMethod ConvertToHttpMethod(string httpMethod) + public static HttpMethod ConvertToHttpMethod(string? httpMethod) { - switch (httpMethod.ToUpperInvariant()) + switch (httpMethod?.ToUpperInvariant()) { case "GET": return HttpMethod.Get; diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index 9e1d208ddf..890637d801 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -10,32 +10,32 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ActionApiDescriptionModel { - public string UniqueName { get; set; } + public string UniqueName { get; set; } = default!; - public string Name { get; set; } + public string Name { get; set; } = default!; - public string HttpMethod { get; set; } + public string? HttpMethod { get; set; } - public string Url { get; set; } + public string Url { get; set; } = default!; - public IList SupportedVersions { get; set; } + public IList? SupportedVersions { get; set; } - public IList ParametersOnMethod { get; set; } + public IList ParametersOnMethod { get; set; } = default!; - public IList Parameters { get; set; } + public IList Parameters { get; set; } = default!; - public ReturnValueApiDescriptionModel ReturnValue { get; set; } + public ReturnValueApiDescriptionModel ReturnValue { get; set; } = default!; public bool? AllowAnonymous { get; set; } - public string ImplementFrom { get; set; } + public string? ImplementFrom { get; set; } public ActionApiDescriptionModel() { } - public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, [CanBeNull] string httpMethod, [NotNull] IList supportedVersions, bool? allowAnonymous = null, string implementFrom = null) + public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, string? httpMethod, [NotNull] IList supportedVersions, bool? allowAnonymous = null, string? implementFrom = null) { Check.NotNull(uniqueName, nameof(uniqueName)); Check.NotNull(method, nameof(method)); diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiTypeNameHelper.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiTypeNameHelper.cs index 6907287f88..a9062655d0 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiTypeNameHelper.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiTypeNameHelper.cs @@ -17,16 +17,16 @@ public static class ApiTypeNameHelper if (TypeHelper.IsDictionary(type, out var keyType, out var valueType)) { - if (!duplicateTypes.Contains(keyType) && !duplicateTypes.Contains(valueType)) + if (!duplicateTypes.Contains(keyType!) && !duplicateTypes.Contains(valueType!)) { - return $"{{{GetTypeName(keyType, duplicateTypes)}:{GetTypeName(valueType, duplicateTypes)}}}"; + return $"{{{GetTypeName(keyType!, duplicateTypes)}:{GetTypeName(valueType!, duplicateTypes)}}}"; } } else if (TypeHelper.IsEnumerable(type, out var itemType, includePrimitives: false)) { - if (!duplicateTypes.Contains(itemType)) + if (!duplicateTypes.Contains(itemType!)) { - return $"[{GetTypeName(itemType, duplicateTypes)}]"; + return $"[{GetTypeName(itemType!, duplicateTypes)}]"; } } @@ -44,16 +44,16 @@ public static class ApiTypeNameHelper if (TypeHelper.IsDictionary(type, out var keyType, out var valueType)) { - if (!duplicateTypes.Contains(keyType) && !duplicateTypes.Contains(valueType)) + if (!duplicateTypes.Contains(keyType!) && !duplicateTypes.Contains(valueType!)) { - return $"{{{GetSimpleTypeName(keyType, duplicateTypes)}:{GetSimpleTypeName(valueType, duplicateTypes)}}}"; + return $"{{{GetSimpleTypeName(keyType!, duplicateTypes)}:{GetSimpleTypeName(valueType!, duplicateTypes)}}}"; } } else if (TypeHelper.IsEnumerable(type, out var itemType, includePrimitives: false)) { - if (!duplicateTypes.Contains(itemType)) + if (!duplicateTypes.Contains(itemType!)) { - return $"[{GetSimpleTypeName(itemType, duplicateTypes)}]"; + return $"[{GetSimpleTypeName(itemType!, duplicateTypes)}]"; } } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs index edebd656cb..03b3751125 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs @@ -8,9 +8,9 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ApplicationApiDescriptionModel { - public IDictionary Modules { get; set; } + public IDictionary Modules { get; set; } = default!; - public IDictionary Types { get; set; } + public IDictionary Types { get; set; } = default!; public ApplicationApiDescriptionModel() { @@ -41,7 +41,7 @@ public class ApplicationApiDescriptionModel return Modules.GetOrAdd(rootPath, () => ModuleApiDescriptionModel.Create(rootPath, remoteServiceName)); } - public ApplicationApiDescriptionModel CreateSubModel(string[] modules = null, string[] controllers = null, string[] actions = null) + public ApplicationApiDescriptionModel CreateSubModel(string[]? modules = null, string[]? controllers = null, string[]? actions = null) { var subModel = ApplicationApiDescriptionModel.Create(); ; diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index e2e0e53e9f..97919e54ba 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -8,28 +8,28 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ControllerApiDescriptionModel { - public string ControllerName { get; set; } + public string ControllerName { get; set; } = default!; - public string ControllerGroupName { get; set; } + public string? ControllerGroupName { get; set; } public bool IsRemoteService { get; set; } public bool IsIntegrationService { get; set; } - public string ApiVersion { get; set; } + public string? ApiVersion { get; set; } - public string Type { get; set; } + public string Type { get; set; } = default!; - public List Interfaces { get; set; } + public List Interfaces { get; set; } = default!; - public Dictionary Actions { get; set; } + public Dictionary Actions { get; set; } = default!; public ControllerApiDescriptionModel() { } - public static ControllerApiDescriptionModel Create(string controllerName, string groupName, bool isRemoteService, bool isIntegrationService, string apiVersion, Type type, [CanBeNull] HashSet ignoredInterfaces = null) + public static ControllerApiDescriptionModel Create(string controllerName, string? groupName, bool isRemoteService, bool isIntegrationService, string? apiVersion, Type type, HashSet? ignoredInterfaces = null) { return new ControllerApiDescriptionModel { @@ -38,11 +38,11 @@ public class ControllerApiDescriptionModel IsRemoteService = isRemoteService, IsIntegrationService = isIntegrationService, //IntegrationServiceAttribute.IsDefinedOrInherited(type), ApiVersion = apiVersion, - Type = type.FullName, + Type = type.FullName!, Actions = new Dictionary(), Interfaces = type .GetInterfaces() - .WhereIf(ignoredInterfaces != null, i => !i.IsGenericType && !ignoredInterfaces.Contains(i)) + .WhereIf(ignoredInterfaces != null, i => !i.IsGenericType && !ignoredInterfaces!.Contains(i)) .Select(ControllerInterfaceApiDescriptionModel.Create) .ToList() }; @@ -60,7 +60,7 @@ public class ControllerApiDescriptionModel return Actions[uniqueName] = action; } - public ControllerApiDescriptionModel CreateSubModel(string[] actions) + public ControllerApiDescriptionModel CreateSubModel(string[]? actions) { var subModel = new ControllerApiDescriptionModel { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs index a0cfe31e26..a95e2ac547 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs @@ -8,11 +8,11 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ControllerInterfaceApiDescriptionModel { - public string Type { get; set; } + public string Type { get; set; } = default!; - public string Name { get; set; } + public string Name { get; set; } = default!; - public InterfaceMethodApiDescriptionModel[] Methods { get; set; } + public InterfaceMethodApiDescriptionModel[] Methods { get; set; } = default!; public ControllerInterfaceApiDescriptionModel() { @@ -23,7 +23,7 @@ public class ControllerInterfaceApiDescriptionModel { var model = new ControllerInterfaceApiDescriptionModel { - Type = type.FullName, + Type = type.FullName!, Name = type.Name }; diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/InterfaceMethodApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/InterfaceMethodApiDescriptionModel.cs index 53a4349854..32b79ce3e1 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/InterfaceMethodApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/InterfaceMethodApiDescriptionModel.cs @@ -9,11 +9,11 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class InterfaceMethodApiDescriptionModel { - public string Name { get; set; } + public string Name { get; set; } = default!; - public IList ParametersOnMethod { get; set; } + public IList ParametersOnMethod { get; set; } = default!; - public ReturnValueApiDescriptionModel ReturnValue { get; set; } + public ReturnValueApiDescriptionModel ReturnValue { get; set; } = default!; public InterfaceMethodApiDescriptionModel() { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs index ed1de76c0e..c3ff20b897 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs @@ -7,17 +7,17 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class MethodParameterApiDescriptionModel { - public string Name { get; set; } + public string Name { get; set; } = default!; - public string TypeAsString { get; set; } + public string TypeAsString { get; set; } = default!; - public string Type { get; set; } + public string Type { get; set; } = default!; - public string TypeSimple { get; set; } + public string TypeSimple { get; set; } = default!; public bool IsOptional { get; set; } - public object DefaultValue { get; set; } + public object? DefaultValue { get; set; } public MethodParameterApiDescriptionModel() { @@ -28,7 +28,7 @@ public class MethodParameterApiDescriptionModel { return new MethodParameterApiDescriptionModel { - Name = parameterInfo.Name, + Name = parameterInfo.Name!, TypeAsString = parameterInfo.ParameterType.GetFullNameWithAssemblyName(), Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(parameterInfo.ParameterType), TypeSimple = ApiTypeNameHelper.GetSimpleTypeName(parameterInfo.ParameterType), diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs index bb2c25e3eb..3a7607376c 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -18,11 +18,11 @@ public class ModuleApiDescriptionModel /// public const string DefaultRemoteServiceName = "Default"; - public string RootPath { get; set; } + public string RootPath { get; set; } = default!; - public string RemoteServiceName { get; set; } + public string RemoteServiceName { get; set; } = default!; - public IDictionary Controllers { get; set; } + public IDictionary Controllers { get; set; } = default!; public ModuleApiDescriptionModel() { @@ -49,13 +49,13 @@ public class ModuleApiDescriptionModel return Controllers[controller.Type] = controller; } - public ControllerApiDescriptionModel GetOrAddController(string name, string groupName, bool isRemoteService, bool isIntegrationService, string apiVersion, Type type, [CanBeNull] HashSet ignoredInterfaces = null) + public ControllerApiDescriptionModel GetOrAddController(string name, string? groupName, bool isRemoteService, bool isIntegrationService, string? apiVersion, Type type, HashSet? ignoredInterfaces = null) { - var key = apiVersion.IsNullOrWhiteSpace() ? type.FullName : $"{apiVersion + "."}{type.FullName}"; + var key = (apiVersion.IsNullOrWhiteSpace() ? type.FullName : $"{apiVersion + "."}{type.FullName}")!; return Controllers.GetOrAdd(key, () => ControllerApiDescriptionModel.Create(name, groupName, isRemoteService, isIntegrationService, apiVersion, type, ignoredInterfaces)); } - public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) + public ModuleApiDescriptionModel CreateSubModel(string[]? controllers, string[]? actions) { var subModel = Create(RootPath, RemoteServiceName); diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs index cf080a857e..a863d1bfad 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs @@ -6,32 +6,32 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ParameterApiDescriptionModel { - public string NameOnMethod { get; set; } + public string NameOnMethod { get; set; } = default!; - public string Name { get; set; } + public string Name { get; set; } = default!; - public string JsonName { get; set; } + public string? JsonName { get; set; } - public string Type { get; set; } + public string? Type { get; set; } - public string TypeSimple { get; set; } + public string? TypeSimple { get; set; } public bool IsOptional { get; set; } - public object DefaultValue { get; set; } + public object? DefaultValue { get; set; } - public string[] ConstraintTypes { get; set; } + public string[]? ConstraintTypes { get; set; } - public string BindingSourceId { get; set; } + public string? BindingSourceId { get; set; } - public string DescriptorName { get; set; } + public string? DescriptorName { get; set; } public ParameterApiDescriptionModel() { } - public static ParameterApiDescriptionModel Create(string name, string jsonName, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null, string descriptorName = null) + public static ParameterApiDescriptionModel Create(string name, string? jsonName, string nameOnMethod, Type type, bool isOptional = false, object? defaultValue = null, string[]? constraintTypes = null, string? bindingSourceId = null, string? descriptorName = null) { return new ParameterApiDescriptionModel { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs index bd3852098b..03aca1fc29 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs @@ -9,13 +9,13 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class PropertyApiDescriptionModel { - public string Name { get; set; } + public string Name { get; set; } = default!; - public string JsonName { get; set; } + public string? JsonName { get; set; } - public string Type { get; set; } + public string Type { get; set; } = default!; - public string TypeSimple { get; set; } + public string TypeSimple { get; set; } = default!; public bool IsRequired { get; set; } @@ -23,11 +23,11 @@ public class PropertyApiDescriptionModel public int? MaxLength { get; set; } - public string Minimum { get; set; } + public string? Minimum { get; set; } - public string Maximum { get; set; } + public string? Maximum { get; set; } - public string Regex { get; set; } + public string? Regex { get; set; } public static PropertyApiDescriptionModel Create(PropertyInfo propertyInfo) { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs index 675eab3c82..e5a7e120a8 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs @@ -7,9 +7,9 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class ReturnValueApiDescriptionModel { - public string Type { get; set; } + public string Type { get; set; } = default!; - public string TypeSimple { get; set; } + public string TypeSimple { get; set; } = default!; public ReturnValueApiDescriptionModel() { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs index 6a9faa71d7..eaeb02f002 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs @@ -7,17 +7,17 @@ namespace Volo.Abp.Http.Modeling; [Serializable] public class TypeApiDescriptionModel { - public string BaseType { get; set; } + public string? BaseType { get; set; } public bool IsEnum { get; set; } - public string[] EnumNames { get; set; } + public string[]? EnumNames { get; set; } - public object[] EnumValues { get; set; } + public object[]? EnumValues { get; set; } - public string[] GenericArguments { get; set; } + public string[]? GenericArguments { get; set; } - public PropertyApiDescriptionModel[] Properties { get; set; } + public PropertyApiDescriptionModel[]? Properties { get; set; } public TypeApiDescriptionModel() { diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs index 86449c8971..eb8ee307b5 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs @@ -5,7 +5,7 @@ namespace Volo.Abp.Http.ProxyScripting.Configuration; public static class AbpApiProxyScriptingConfiguration { - public static Func PropertyNameGenerator { get; set; } + public static Func PropertyNameGenerator { get; set; } static AbpApiProxyScriptingConfiguration() { 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 f7383f0465..b5973eed8a 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 @@ -135,16 +135,16 @@ public class JQueryProxyScriptGenerator : IProxyScriptGenerator, ITransientDepen private static string FindBestApiVersion(ActionApiDescriptionModel action) { //var configuredVersion = GetConfiguredApiVersion(); //TODO: Implement - string configuredVersion = null; + string? configuredVersion = null; if (action.SupportedVersions.IsNullOrEmpty()) { return configuredVersion ?? "1.0"; } - if (action.SupportedVersions.Contains(configuredVersion)) + if (action.SupportedVersions!.Contains(configuredVersion!)) { - return configuredVersion; + return configuredVersion!; } return action.SupportedVersions.Last(); //TODO: Ensure to get the latest version! diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/ProxyScriptingHelper.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/ProxyScriptingHelper.cs index 4b43eb70c7..40cc5c4719 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/ProxyScriptingHelper.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/ProxyScriptingHelper.cs @@ -25,7 +25,7 @@ internal static class ProxyScriptingHelper } } - public static string GenerateHeaders(ActionApiDescriptionModel action, int indent = 0) + public static string? GenerateHeaders(ActionApiDescriptionModel action, int indent = 0) { var parameters = action .Parameters @@ -40,7 +40,7 @@ internal static class ProxyScriptingHelper return ProxyScriptingJsFuncHelper.CreateJsObjectLiteral(parameters, indent); } - public static string GenerateBody(ActionApiDescriptionModel action) + public static string? GenerateBody(ActionApiDescriptionModel action) { var parameters = action .Parameters @@ -62,7 +62,7 @@ internal static class ProxyScriptingHelper return ProxyScriptingJsFuncHelper.GetParamNameInJsFunc(parameters[0]); } - public static string GenerateFormPostData(ActionApiDescriptionModel action, int indent = 0) + public static string? GenerateFormPostData(ActionApiDescriptionModel action, int indent = 0) { var parameters = action .Parameters diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs index b165977076..e3eecb0f60 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs @@ -8,11 +8,11 @@ public class ProxyScriptingModel public bool UseCache { get; set; } - public string[] Modules { get; set; } + public string[]? Modules { get; set; } - public string[] Controllers { get; set; } + public string[]? Controllers { get; set; } - public string[] Actions { get; set; } + public string[]? Actions { get; set; } public IDictionary Properties { get; set; } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj index a707f58b9c..b0c2b3e567 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj +++ b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.IdentityModel Volo.Abp.IdentityModel $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityClientOptions.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityClientOptions.cs index 364d2dc2ea..62fc21a5fa 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityClientOptions.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityClientOptions.cs @@ -14,7 +14,7 @@ public class AbpIdentityClientOptions IdentityClients = new IdentityClientConfigurationDictionary(); } - public IdentityClientConfiguration GetClientConfiguration(ICurrentTenant currentTenant, string identityClientName = null) + public IdentityClientConfiguration? GetClientConfiguration(ICurrentTenant currentTenant, string? identityClientName = null) { if (identityClientName.IsNullOrWhiteSpace()) { @@ -35,7 +35,7 @@ public class AbpIdentityClientOptions } } - return IdentityClients.GetOrDefault(identityClientName) ?? + return IdentityClients.GetOrDefault(identityClientName!) ?? IdentityClients.Default; } } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IIdentityModelAuthenticationService.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IIdentityModelAuthenticationService.cs index fee1a032fb..8a5902bdbf 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IIdentityModelAuthenticationService.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IIdentityModelAuthenticationService.cs @@ -9,7 +9,7 @@ public interface IIdentityModelAuthenticationService { Task TryAuthenticateAsync( [NotNull] HttpClient client, - string identityClientName = null); + string? identityClientName = null); Task GetAccessTokenAsync( IdentityClientConfiguration configuration); diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs index 8faf3225ab..011e40b4b3 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs @@ -5,14 +5,14 @@ using IdentityModel; namespace Volo.Abp.IdentityModel; -public class IdentityClientConfiguration : Dictionary +public class IdentityClientConfiguration : Dictionary { /// /// Possible values: "client_credentials" or "password". /// Default value: "client_credentials". /// public string GrantType { - get => this.GetOrDefault(nameof(GrantType)); + get => this.GetOrDefault(nameof(GrantType))!; set => this[nameof(GrantType)] = value; } @@ -20,7 +20,7 @@ public class IdentityClientConfiguration : Dictionary /// Client Id. /// public string ClientId { - get => this.GetOrDefault(nameof(ClientId)); + get => this.GetOrDefault(nameof(ClientId))!; set => this[nameof(ClientId)] = value; } @@ -28,7 +28,7 @@ public class IdentityClientConfiguration : Dictionary /// Client secret (as plain text - without hashed). /// public string ClientSecret { - get => this.GetOrDefault(nameof(ClientSecret)); + get => this.GetOrDefault(nameof(ClientSecret))!; set => this[nameof(ClientSecret)] = value; } @@ -36,7 +36,7 @@ public class IdentityClientConfiguration : Dictionary /// User name. /// Valid only if is "password". /// - public string UserName { + public string? UserName { get => this.GetOrDefault(nameof(UserName)); set => this[nameof(UserName)] = value; } @@ -45,7 +45,7 @@ public class IdentityClientConfiguration : Dictionary /// Password of the . /// Valid only if is "password". /// - public string UserPassword { + public string? UserPassword { get => this.GetOrDefault(nameof(UserPassword)); set => this[nameof(UserPassword)] = value; } @@ -54,7 +54,7 @@ public class IdentityClientConfiguration : Dictionary /// Authority. /// public string Authority { - get => this.GetOrDefault(nameof(Authority)); + get => this.GetOrDefault(nameof(Authority))!; set => this[nameof(Authority)] = value; } @@ -62,7 +62,7 @@ public class IdentityClientConfiguration : Dictionary /// Scope. /// public string Scope { - get => this.GetOrDefault(nameof(Scope)); + get => this.GetOrDefault(nameof(Scope))!; set => this[nameof(Scope)] = value; } @@ -113,8 +113,8 @@ public class IdentityClientConfiguration : Dictionary string clientId, string clientSecret, string grantType = OidcConstants.GrantTypes.ClientCredentials, - string userName = null, - string userPassword = null, + string? userName = null, + string? userPassword = null, bool requireHttps = true, int cacheAbsoluteExpiration = 60 * 30, bool validateIssuerName = true, diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfigurationDictionary.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfigurationDictionary.cs index e8c42fe390..4993cfa462 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfigurationDictionary.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfigurationDictionary.cs @@ -2,11 +2,11 @@ namespace Volo.Abp.IdentityModel; -public class IdentityClientConfigurationDictionary : Dictionary +public class IdentityClientConfigurationDictionary : Dictionary { public const string DefaultName = "Default"; - public IdentityClientConfiguration Default { + public IdentityClientConfiguration? Default { get => this.GetOrDefault(DefaultName); set => this[DefaultName] = value; } 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 6f5f8eda95..4354d83735 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs @@ -54,7 +54,7 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe public async Task TryAuthenticateAsync( [NotNull] HttpClient client, - string identityClientName = null) + string? identityClientName = null) { var accessToken = await GetAccessTokenOrNullAsync(identityClientName); if (accessToken == null) @@ -66,7 +66,7 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe return true; } - protected virtual async Task GetAccessTokenOrNullAsync(string identityClientName) + protected virtual async Task GetAccessTokenOrNullAsync(string? identityClientName) { var configuration = ClientOptions.GetClientConfiguration(CurrentTenant, identityClientName); if (configuration == null) diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs index 0fbf50d020..6cabe5d9b9 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs @@ -7,9 +7,9 @@ namespace Volo.Abp.IdentityModel; [IgnoreMultiTenancy] public class IdentityModelDiscoveryDocumentCacheItem { - public string TokenEndpoint { get; set; } + public string TokenEndpoint { get; set; } = default!; - public string DeviceAuthorizationEndpoint { get; set; } + public string DeviceAuthorizationEndpoint { get; set; } = default!; public IdentityModelDiscoveryDocumentCacheItem() { diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelHttpRequestMessageOptions.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelHttpRequestMessageOptions.cs index d72cc9682e..78b2a342f4 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelHttpRequestMessageOptions.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelHttpRequestMessageOptions.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.IdentityModel; public class IdentityModelHttpRequestMessageOptions { - public Action ConfigureHttpRequestMessage { get; set; } + public Action? ConfigureHttpRequestMessage { get; set; } } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs index 2a164a23e6..72beed1577 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.IdentityModel; [Serializable] public class IdentityModelTokenCacheItem { - public string AccessToken { get; set; } + public string AccessToken { get; set; } = default!; public IdentityModelTokenCacheItem() { diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo.Abp.Imaging.Abstractions.csproj b/framework/src/Volo.Abp.Imaging.Abstractions/Volo.Abp.Imaging.Abstractions.csproj index 6b7c0434ed..288f43c7d4 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo.Abp.Imaging.Abstractions.csproj +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo.Abp.Imaging.Abstractions.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Imaging.Abstractions $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressor.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressor.cs index 949a3fb848..6d80cd1c6b 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressor.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressor.cs @@ -9,13 +9,13 @@ public interface IImageCompressor { Task> CompressAsync( Stream stream, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default ); Task> CompressAsync( byte[] bytes, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default ); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressorContributor.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressorContributor.cs index 84087d983a..7fc9362c77 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressorContributor.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageCompressorContributor.cs @@ -9,10 +9,10 @@ public interface IImageCompressorContributor { Task> TryCompressAsync( Stream stream, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default); Task> TryCompressAsync( byte[] bytes, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizer.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizer.cs index c2ae1b62e9..2c9c2878ed 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizer.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizer.cs @@ -10,14 +10,14 @@ public interface IImageResizer Task> ResizeAsync( Stream stream, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default ); Task> ResizeAsync( byte[] bytes, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default ); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizerContributor.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizerContributor.cs index fed4ce4a4c..a6603ea136 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizerContributor.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/IImageResizerContributor.cs @@ -10,12 +10,12 @@ public interface IImageResizerContributor Task> TryResizeAsync( Stream stream, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default); Task> TryResizeAsync( byte[] bytes, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageCompressor.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageCompressor.cs index 11789776c7..d36a9d6ea0 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageCompressor.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageCompressor.cs @@ -23,7 +23,7 @@ public class ImageCompressor : IImageCompressor, ITransientDependency public virtual async Task> CompressAsync( [NotNull] Stream stream, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { Check.NotNull(stream, nameof(stream)); @@ -45,7 +45,7 @@ public class ImageCompressor : IImageCompressor, ITransientDependency public virtual async Task> CompressAsync( [NotNull] byte[] bytes, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { Check.NotNull(bytes, nameof(bytes)); diff --git a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageResizer.cs b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageResizer.cs index 139fc194dd..e2c4ad7d77 100644 --- a/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageResizer.cs +++ b/framework/src/Volo.Abp.Imaging.Abstractions/Volo/Abp/Imaging/ImageResizer.cs @@ -31,7 +31,7 @@ public class ImageResizer : IImageResizer, ITransientDependency public virtual async Task> ResizeAsync( [NotNull] Stream stream, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { Check.NotNull(stream, nameof(stream)); @@ -56,7 +56,7 @@ public class ImageResizer : IImageResizer, ITransientDependency public virtual async Task> ResizeAsync( [NotNull] byte[] bytes, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { Check.NotNull(bytes, nameof(bytes)); diff --git a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo.Abp.Imaging.AspNetCore.csproj b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo.Abp.Imaging.AspNetCore.csproj index d727d99a7c..8b8810e000 100644 --- a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo.Abp.Imaging.AspNetCore.csproj +++ b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo.Abp.Imaging.AspNetCore.csproj @@ -5,6 +5,8 @@ net7.0 + enable + Nullable Volo.Abp.Imaging.AspNetCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false diff --git a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/CompressImageAttribute.cs b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/CompressImageAttribute.cs index 1ddd8822be..e49a5abc9f 100644 --- a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/CompressImageAttribute.cs +++ b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/CompressImageAttribute.cs @@ -28,7 +28,7 @@ public class CompressImageAttribute : ActionFilterAttribute foreach (var (key, value) in parameters) { - object compressedValue = value switch { + object? compressedValue = value switch { IFormFile file => await CompressImageAsync(file, imageCompressor), IRemoteStreamContent remoteStreamContent => await CompressImageAsync(remoteStreamContent, imageCompressor), Stream stream => await CompressImageAsync(stream, imageCompressor), diff --git a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/ResizeImageAttribute.cs b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/ResizeImageAttribute.cs index 799cd81877..65b59bef6f 100644 --- a/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/ResizeImageAttribute.cs +++ b/framework/src/Volo.Abp.Imaging.AspNetCore/Volo/Abp/Imaging/ResizeImageAttribute.cs @@ -41,7 +41,7 @@ public class ResizeImageAttribute : ActionFilterAttribute foreach (var (key, value) in parameters) { - object resizedValue = value switch { + object? resizedValue = value switch { IFormFile file => await ResizeImageAsync(file, imageResizer), IRemoteStreamContent remoteStreamContent => await ResizeImageAsync(remoteStreamContent, imageResizer), Stream stream => await ResizeImageAsync(stream, imageResizer), diff --git a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo.Abp.Imaging.ImageSharp.csproj b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo.Abp.Imaging.ImageSharp.csproj index d523a292ba..29d6a3944e 100644 --- a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo.Abp.Imaging.ImageSharp.csproj +++ b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo.Abp.Imaging.ImageSharp.csproj @@ -5,6 +5,8 @@ netstandard2.0; + enable + Nullable Volo.Abp.Imaging.ImageSharp $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false diff --git a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs index a54d006b30..8d2f29dd02 100644 --- a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs +++ b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs @@ -26,7 +26,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, public virtual async Task> TryCompressAsync( Stream stream, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanCompress(mimeType)) @@ -54,7 +54,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, public virtual async Task> TryCompressAsync( byte[] bytes, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanCompress(mimeType)) @@ -75,7 +75,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, return new ImageCompressResult(newBytes, result.State); } - protected virtual bool CanCompress(string mimeType) + protected virtual bool CanCompress(string? mimeType) { return mimeType switch { MimeTypes.Image.Jpeg => true, diff --git a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs index d2ac92eaf7..92dbc25034 100644 --- a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs +++ b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs @@ -16,7 +16,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran public virtual async Task> TryResizeAsync( Stream stream, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanResize(mimeType)) @@ -58,7 +58,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran public virtual async Task> TryResizeAsync( byte[] bytes, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanResize(mimeType)) @@ -82,7 +82,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran return new ImageResizeResult(newBytes, result.State); } - protected virtual bool CanResize(string mimeType) + protected virtual bool CanResize(string? mimeType) { return mimeType switch { MimeTypes.Image.Jpeg => true, diff --git a/framework/src/Volo.Abp.Imaging.MagickNet/Volo.Abp.Imaging.MagickNet.csproj b/framework/src/Volo.Abp.Imaging.MagickNet/Volo.Abp.Imaging.MagickNet.csproj index 535f689663..0e3581908a 100644 --- a/framework/src/Volo.Abp.Imaging.MagickNet/Volo.Abp.Imaging.MagickNet.csproj +++ b/framework/src/Volo.Abp.Imaging.MagickNet/Volo.Abp.Imaging.MagickNet.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Imaging.MagicNet $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; false diff --git a/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageCompressorContributor.cs b/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageCompressorContributor.cs index a0900cd14a..3aba7f5000 100644 --- a/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageCompressorContributor.cs +++ b/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageCompressorContributor.cs @@ -28,7 +28,7 @@ public class MagickImageCompressorContributor : IImageCompressorContributor, ITr public virtual async Task> TryCompressAsync( Stream stream, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanCompress(mimeType)) @@ -63,7 +63,7 @@ public class MagickImageCompressorContributor : IImageCompressorContributor, ITr public virtual async Task> TryCompressAsync( byte[] bytes, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(mimeType) && !CanCompress(mimeType)) @@ -86,7 +86,7 @@ public class MagickImageCompressorContributor : IImageCompressorContributor, ITr return new ImageCompressResult(newBytes, result.State); } - protected virtual bool CanCompress(string mimeType) + protected virtual bool CanCompress(string? mimeType) { return mimeType switch { MimeTypes.Image.Jpeg => true, diff --git a/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageResizerContributor.cs b/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageResizerContributor.cs index 9ffb6133e5..b71230e8bb 100644 --- a/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageResizerContributor.cs +++ b/framework/src/Volo.Abp.Imaging.MagickNet/Volo/Abp/Imaging/MagickImageResizerContributor.cs @@ -16,7 +16,7 @@ public class MagickImageResizerContributor : IImageResizerContributor, ITransien public virtual async Task> TryResizeAsync( Stream stream, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!mimeType.IsNullOrWhiteSpace() && !CanResize(mimeType)) @@ -54,7 +54,7 @@ public class MagickImageResizerContributor : IImageResizerContributor, ITransien public virtual Task> TryResizeAsync( byte[] bytes, ImageResizeArgs resizeArgs, - [CanBeNull] string mimeType = null, + string? mimeType = null, CancellationToken cancellationToken = default) { if (!mimeType.IsNullOrWhiteSpace() && !CanResize(mimeType)) @@ -74,7 +74,7 @@ public class MagickImageResizerContributor : IImageResizerContributor, ITransien return Task.FromResult(new ImageResizeResult(image.ToByteArray(), ImageProcessState.Done)); } - protected virtual bool CanResize(string mimeType) + protected virtual bool CanResize(string? mimeType) { return mimeType switch { MimeTypes.Image.Jpeg => true, diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj index 40049addba..67dfaf2a28 100644 --- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj +++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.Json Volo.Abp.Json $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Kafka/Volo.Abp.Kafka.csproj b/framework/src/Volo.Abp.Kafka/Volo.Abp.Kafka.csproj index f66761fc2a..e56bd38916 100644 --- a/framework/src/Volo.Abp.Kafka/Volo.Abp.Kafka.csproj +++ b/framework/src/Volo.Abp.Kafka/Volo.Abp.Kafka.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/AbpKafkaOptions.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/AbpKafkaOptions.cs index b48a952615..11b443f72b 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/AbpKafkaOptions.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/AbpKafkaOptions.cs @@ -8,11 +8,11 @@ public class AbpKafkaOptions { public KafkaConnections Connections { get; } - public Action ConfigureProducer { get; set; } + public Action? ConfigureProducer { get; set; } - public Action ConfigureConsumer { get; set; } + public Action? ConfigureConsumer { get; set; } - public Action ConfigureTopic { get; set; } + public Action? ConfigureTopic { get; set; } public AbpKafkaOptions() { diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs index 7c73df0d51..48943c84c4 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs @@ -30,7 +30,7 @@ public class ConsumerPool : IConsumerPool, ISingletonDependency Logger = new NullLogger(); } - public virtual IConsumer Get(string groupId, string connectionName = null) + public virtual IConsumer Get(string groupId, string? connectionName = null) { connectionName ??= KafkaConnections.DefaultConnectionName; diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IConsumerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IConsumerPool.cs index 4666a0175f..a3f484ef56 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IConsumerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IConsumerPool.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.Kafka; public interface IConsumerPool : IDisposable { - IConsumer Get(string groupId, string connectionName = null); + IConsumer Get(string groupId, string? connectionName = null); } diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs index e21c8c9fd2..985e20625f 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IKafkaMessageConsumerFactory.cs @@ -14,5 +14,5 @@ public interface IKafkaMessageConsumerFactory IKafkaMessageConsumer Create( string topicName, string groupId, - string connectionName = null); + string? connectionName = null); } diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IProducerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IProducerPool.cs index 8930184016..378075b2ec 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IProducerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/IProducerPool.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.Kafka; public interface IProducerPool : IDisposable { - IProducer Get(string connectionName = null); + IProducer Get(string? connectionName = null); } diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaConnections.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaConnections.cs index 3d9f2fe950..e66e074ad6 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaConnections.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaConnections.cs @@ -21,8 +21,10 @@ public class KafkaConnections : Dictionary Default = new ClientConfig(); } - public ClientConfig GetOrDefault(string connectionName) + public ClientConfig GetOrDefault(string? connectionName) { + connectionName ??= DefaultConnectionName; + if (TryGetValue(connectionName, out var connectionFactory)) { return connectionFactory; diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs index 704c15845f..5a2ba38189 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumer.cs @@ -31,13 +31,13 @@ public class KafkaMessageConsumer : IKafkaMessageConsumer, ITransientDependency, protected ConcurrentBag, Task>> Callbacks { get; } - protected IConsumer Consumer { get; private set; } + protected IConsumer? Consumer { get; private set; } - protected string ConnectionName { get; private set; } + protected string? ConnectionName { get; private set; } - protected string GroupId { get; private set; } + protected string GroupId { get; private set; } = default!; - protected string TopicName { get; private set; } + protected string TopicName { get; private set; } = default!; public KafkaMessageConsumer( IConsumerPool consumerPool, @@ -63,7 +63,7 @@ public class KafkaMessageConsumer : IKafkaMessageConsumer, ITransientDependency, public virtual void Initialize( [NotNull] string topicName, [NotNull] string groupId, - string connectionName = null) + string? connectionName = null) { Check.NotNull(topicName, nameof(topicName)); Check.NotNull(groupId, nameof(groupId)); @@ -160,7 +160,7 @@ public class KafkaMessageConsumer : IKafkaMessageConsumer, ITransientDependency, } finally { - Consumer.Commit(consumeResult); + Consumer?.Commit(consumeResult); } } diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs index dfc5912d55..fe46b5fe38 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/KafkaMessageConsumerFactory.cs @@ -16,7 +16,7 @@ public class KafkaMessageConsumerFactory : IKafkaMessageConsumerFactory, ISingle public IKafkaMessageConsumer Create( string topicName, string groupId, - string connectionName = null) + string? connectionName = null) { var consumer = ServiceScope.ServiceProvider.GetRequiredService(); consumer.Initialize(topicName, groupId, connectionName); diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs index ac2edf31a7..23b9b71a57 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs @@ -32,7 +32,7 @@ public class ProducerPool : IProducerPool, ISingletonDependency Logger = new NullLogger(); } - public virtual IProducer Get(string connectionName = null) + public virtual IProducer Get(string? connectionName = null) { connectionName ??= KafkaConnections.DefaultConnectionName; diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs index c3523b4e1a..96e436760e 100644 --- a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs @@ -29,7 +29,7 @@ public class MailKitSmtpEmailSender : EmailSenderBase, IMailKitSmtpEmailSender SmtpConfiguration = smtpConfiguration; } - protected override async Task SendEmailAsync(MailMessage mail) + protected async override Task SendEmailAsync(MailMessage mail) { using (var client = await BuildClientAsync()) { diff --git a/framework/src/Volo.Abp.MemoryDb/Microsoft/Extensions/DependencyInjection/AbpMemoryDbServiceCollectionExtensions.cs b/framework/src/Volo.Abp.MemoryDb/Microsoft/Extensions/DependencyInjection/AbpMemoryDbServiceCollectionExtensions.cs index 0f06706180..d14d8d657e 100644 --- a/framework/src/Volo.Abp.MemoryDb/Microsoft/Extensions/DependencyInjection/AbpMemoryDbServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.MemoryDb/Microsoft/Extensions/DependencyInjection/AbpMemoryDbServiceCollectionExtensions.cs @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class AbpMemoryDbServiceCollectionExtensions { - public static IServiceCollection AddMemoryDbContext(this IServiceCollection services, Action optionsBuilder = null) + public static IServiceCollection AddMemoryDbContext(this IServiceCollection services, Action? optionsBuilder = null) where TMemoryDbContext : MemoryDbContext { var options = new AbpMemoryDbContextRegistrationOptions(typeof(TMemoryDbContext), services); diff --git a/framework/src/Volo.Abp.MemoryDb/Volo.Abp.MemoryDb.csproj b/framework/src/Volo.Abp.MemoryDb/Volo.Abp.MemoryDb.csproj index 07ddca1d7a..5f4f78a5db 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo.Abp.MemoryDb.csproj +++ b/framework/src/Volo.Abp.MemoryDb/Volo.Abp.MemoryDb.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.MemoryDb Volo.Abp.MemoryDb $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabase.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabase.cs index c3103e20f2..a38aeec1b2 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabase.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDatabase.cs @@ -25,9 +25,9 @@ public class MemoryDatabase : IMemoryDatabase, ITransientDependency public IMemoryDatabaseCollection Collection() where TEntity : class, IEntity { - return _sets.GetOrAdd(typeof(TEntity), + return (_sets.GetOrAdd(typeof(TEntity), _ => _serviceProvider.GetRequiredService>()) as - IMemoryDatabaseCollection; + IMemoryDatabaseCollection)!; } public TKey GenerateNextId() diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 39b2247a61..186edd7d33 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -192,7 +192,7 @@ public class MemoryDbRepository : RepositoryBase FindAsync( + public override async Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -340,14 +340,14 @@ public class MemoryDbRepository : MemoryDbRepos return entity; } - public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - return (await GetQueryableAsync()).FirstOrDefault(e => e.Id.Equals(id)); + return (await GetQueryableAsync()).FirstOrDefault(e => e.Id!.Equals(id)); } public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - await DeleteAsync(x => x.Id.Equals(id), autoSave, cancellationToken); + await DeleteAsync(x => x.Id!.Equals(id), autoSave, cancellationToken); } public virtual async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs index deff9658fb..1a901820f3 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs @@ -21,6 +21,6 @@ public class Utf8JsonMemoryDbSerializer : IMemoryDbSerializer, ITransientDepende public object Deserialize(byte[] value, Type type) { - return JsonSerializer.Deserialize(value, type, Options.JsonSerializerOptions); + return JsonSerializer.Deserialize(value, type, Options.JsonSerializerOptions)!; } } diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/DependencyInjection/MemoryDbRepositoryRegistrar.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/DependencyInjection/MemoryDbRepositoryRegistrar.cs index d746c65acf..21fddd50d2 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/DependencyInjection/MemoryDbRepositoryRegistrar.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/DependencyInjection/MemoryDbRepositoryRegistrar.cs @@ -14,7 +14,7 @@ public class MemoryDbRepositoryRegistrar : RepositoryRegistrarBase GetEntityTypes(Type dbContextType) { - var memoryDbContext = (MemoryDbContext)Activator.CreateInstance(dbContextType); + var memoryDbContext = (MemoryDbContext)Activator.CreateInstance(dbContextType)!; return memoryDbContext.GetEntityTypes(); } diff --git a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs index 872c591c8a..71b6231ef7 100644 --- a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class AbpMongoDbServiceCollectionExtensions { - public static IServiceCollection AddMongoDbContext(this IServiceCollection services, Action optionsBuilder = null) //Created overload instead of default parameter + public static IServiceCollection AddMongoDbContext(this IServiceCollection services, Action? optionsBuilder = null) //Created overload instead of default parameter where TMongoDbContext : AbpMongoDbContext { var options = new AbpMongoDbContextRegistrationOptions(typeof(TMongoDbContext), services); diff --git a/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj b/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj index 5857929d00..c364a2b0e0 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj +++ b/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable Volo.Abp.MongoDB Volo.Abp.MongoDB $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbBulkOperationProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbBulkOperationProvider.cs index 47853f24d6..eb8d04d52c 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbBulkOperationProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbBulkOperationProvider.cs @@ -11,7 +11,7 @@ public interface IMongoDbBulkOperationProvider Task InsertManyAsync( IMongoDbRepository repository, IEnumerable entities, - IClientSessionHandle sessionHandle, + IClientSessionHandle? sessionHandle, bool autoSave, CancellationToken cancellationToken ) @@ -20,7 +20,7 @@ public interface IMongoDbBulkOperationProvider Task UpdateManyAsync( IMongoDbRepository repository, IEnumerable entities, - IClientSessionHandle sessionHandle, + IClientSessionHandle? sessionHandle, bool autoSave, CancellationToken cancellationToken ) @@ -29,7 +29,7 @@ public interface IMongoDbBulkOperationProvider Task DeleteManyAsync( IMongoDbRepository repository, IEnumerable entities, - IClientSessionHandle sessionHandle, + IClientSessionHandle? sessionHandle, bool autoSave, CancellationToken cancellationToken ) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs index eeac0dc2e2..a687ba2bf9 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs @@ -23,9 +23,9 @@ public interface IMongoDbRepository : IRepository [Obsolete("Use GetMongoQueryableAsync method.")] IMongoQueryable GetMongoQueryable(); - Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions options = null); + Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null); - Task> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions options = null); + Task> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null); } public interface IMongoDbRepository : IMongoDbRepository, IRepository diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs index 1fff832d76..f02beed826 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs @@ -17,7 +17,7 @@ public interface IMongoDbRepositoryFilterer : IMongoDbRepositoryF { Task> CreateEntityFilterAsync(TKey id, bool applyFilters = false); - Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null); + Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string? concurrencyStamp = null); /// /// Creates filter for given entities. diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 4ebe61f64e..8c3f3e2526 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -43,9 +43,9 @@ public class MongoDbRepository } [Obsolete("Use GetSessionHandleAsync method.")] - protected virtual IClientSessionHandle SessionHandle => DbContext.SessionHandle; + protected virtual IClientSessionHandle? SessionHandle => DbContext.SessionHandle; - protected async Task GetSessionHandleAsync(CancellationToken cancellationToken = default) + protected async Task GetSessionHandleAsync(CancellationToken cancellationToken = default) { return (await GetDbContextAsync(GetCancellationToken(cancellationToken))).SessionHandle; } @@ -96,9 +96,9 @@ public class MongoDbRepository public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService(); - public IMongoDbBulkOperationProvider BulkOperationProvider => LazyServiceProvider.LazyGetService(); + public IMongoDbBulkOperationProvider? BulkOperationProvider => LazyServiceProvider.LazyGetService(); - public IMongoDbRepositoryFilterer RepositoryFilterer => LazyServiceProvider.LazyGetService>(); + public IMongoDbRepositoryFilterer RepositoryFilterer => LazyServiceProvider.LazyGetService>()!; public MongoDbRepository(IMongoDbContextProvider dbContextProvider) { @@ -382,7 +382,7 @@ public class MongoDbRepository if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity)) { ObjectHelper.TrySetProperty(((ISoftDelete)entity), x => x.IsDeleted, () => true); - softDeletedEntities.Add(entity, SetNewConcurrencyStamp(entity)); + softDeletedEntities.Add(entity, SetNewConcurrencyStamp(entity)!); } else { @@ -525,7 +525,7 @@ public class MongoDbRepository return await GetMongoQueryableAsync(); } - public async override Task FindAsync( + public async override Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -547,12 +547,12 @@ public class MongoDbRepository ); } - public virtual Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions aggregateOptions = null) + public virtual Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) { return GetMongoQueryableAsync(cancellationToken, aggregateOptions); } - protected virtual async Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions aggregateOptions = null) + protected virtual async Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) { cancellationToken = GetCancellationToken(cancellationToken); @@ -566,7 +566,7 @@ public class MongoDbRepository ); } - public virtual async Task> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions aggregateOptions = null) + public virtual async Task> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) { cancellationToken = GetCancellationToken(cancellationToken); @@ -602,7 +602,7 @@ public class MongoDbRepository return hardDeletedEntities.Contains(entity); } - protected virtual Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null) + protected virtual Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string? concurrencyStamp = null) { throw new NotImplementedException( $"{nameof(CreateEntityFilterAsync)} is not implemented for MongoDB by default. It should be overriden and implemented by the deriving class!" @@ -737,7 +737,7 @@ public class MongoDbRepository /// if given entity implements interface. /// Returns the old value. /// - protected virtual string SetNewConcurrencyStamp(TEntity entity) + protected virtual string? SetNewConcurrencyStamp(TEntity entity) { if (!(entity is IHasConcurrencyStamp concurrencyStampEntity)) { @@ -770,7 +770,7 @@ public class MongoDbRepository where TMongoDbContext : IAbpMongoDbContext where TEntity : class, IEntity { - public IMongoDbRepositoryFilterer RepositoryFiltererWithKey => LazyServiceProvider.LazyGetService>(); + public IMongoDbRepositoryFilterer RepositoryFiltererWithKey => LazyServiceProvider.LazyGetService>()!; public MongoDbRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) @@ -793,14 +793,14 @@ public class MongoDbRepository return entity; } - public virtual async Task FindAsync( + public virtual async Task FindAsync( TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { cancellationToken = GetCancellationToken(cancellationToken); - return await ApplyDataFilters(await GetMongoQueryableAsync(cancellationToken)).Where(x => x.Id.Equals(id)).FirstOrDefaultAsync(cancellationToken); + return await ApplyDataFilters(await GetMongoQueryableAsync(cancellationToken)).Where(x => x.Id!.Equals(id)).FirstOrDefaultAsync(cancellationToken); } public virtual Task DeleteAsync( @@ -808,7 +808,7 @@ public class MongoDbRepository bool autoSave = false, CancellationToken cancellationToken = default) { - return DeleteAsync(x => x.Id.Equals(id), autoSave, cancellationToken); + return DeleteAsync(x => x.Id!.Equals(id), autoSave, cancellationToken); } public virtual async Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) @@ -832,7 +832,7 @@ public class MongoDbRepository return base.ApplyDataFilters(query); } - protected async override Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null) + protected async override Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string? concurrencyStamp = null) { return await RepositoryFiltererWithKey.CreateEntityFilterAsync(entity, withConcurrencyStamp, concurrencyStamp); } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs index 83063dae4c..97358fb7e8 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs @@ -67,7 +67,7 @@ public class MongoDbRepositoryFilterer : MongoDbRepositoryFiltere return Builders.Filter.And(filters); } - public virtual Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null) + public virtual Task> CreateEntityFilterAsync(TEntity entity, bool withConcurrencyStamp = false, string? concurrencyStamp = null) { if (!withConcurrencyStamp || !(entity is IHasConcurrencyStamp entityWithConcurrencyStamp)) { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs index c71c3e991d..676450a5b8 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs @@ -43,13 +43,13 @@ public static class MongoDbCoreRepositoryExtensions return repository.ToMongoDbRepository().GetMongoQueryable(); } - public static Task> GetMongoQueryableAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default, AggregateOptions aggregateOptions = null) + public static Task> GetMongoQueryableAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetMongoQueryableAsync(cancellationToken, aggregateOptions); } - public static Task> GetAggregateAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default, AggregateOptions aggregateOptions = null) + public static Task> GetAggregateAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetAggregateAsync(cancellationToken, aggregateOptions); diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs index e1388d61ca..ba89c81c29 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs @@ -6,22 +6,22 @@ namespace Volo.Abp.MongoDB; public abstract class AbpMongoDbContext : IAbpMongoDbContext, ITransientDependency { - public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; - public IMongoModelSource ModelSource { get; set; } + public IMongoModelSource ModelSource { get; set; } = default!; - public IMongoClient Client { get; private set; } + public IMongoClient Client { get; private set; } = default!; - public IMongoDatabase Database { get; private set; } + public IMongoDatabase Database { get; private set; } = default!; - public IClientSessionHandle SessionHandle { get; private set; } + public IClientSessionHandle? SessionHandle { get; private set; } protected internal virtual void CreateModel(IMongoModelBuilder modelBuilder) { } - public virtual void InitializeDatabase(IMongoDatabase database, IMongoClient client, IClientSessionHandle sessionHandle) + public virtual void InitializeDatabase(IMongoDatabase database, IMongoClient client, IClientSessionHandle? sessionHandle) { Database = database; Client = client; diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs index eb9188a601..36ff84a64f 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs @@ -12,7 +12,7 @@ public class AbpMongoDbContextOptions { internal Dictionary DbContextReplacements { get; } - public Action MongoClientSettingsConfigurer { get; set; } + public Action? MongoClientSettingsConfigurer { get; set; } public AbpMongoDbContextOptions() { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoModelBuilderConfigurationOptions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoModelBuilderConfigurationOptions.cs index 182e17a61a..e42fa46a32 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoModelBuilderConfigurationOptions.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoModelBuilderConfigurationOptions.cs @@ -12,7 +12,8 @@ public class AbpMongoModelBuilderConfigurationOptions _collectionPrefix = value; } } - private string _collectionPrefix; + + private string _collectionPrefix = default!; public AbpMongoModelBuilderConfigurationOptions([NotNull] string collectionPrefix = "") { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/IncomingEventRecord.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/IncomingEventRecord.cs index e6ddc87bd6..4b66c58595 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/IncomingEventRecord.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/IncomingEventRecord.cs @@ -15,11 +15,11 @@ public class IncomingEventRecord : public ExtraPropertyDictionary ExtraProperties { get; private set; } - public string MessageId { get; private set; } + public string MessageId { get; private set; } = default!; - public string EventName { get; private set; } + public string EventName { get; private set; } = default!; - public byte[] EventData { get; private set; } + public byte[] EventData { get; private set; } = default!; public DateTime CreationTime { get; private set; } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/OutgoingEventRecord.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/OutgoingEventRecord.cs index 0f0798532b..a7f3d5ab14 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/OutgoingEventRecord.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/OutgoingEventRecord.cs @@ -15,9 +15,9 @@ public class OutgoingEventRecord : public ExtraPropertyDictionary ExtraProperties { get; private set; } - public string EventName { get; private set; } + public string EventName { get; private set; } = default!; - public byte[] EventData { get; private set; } + public byte[] EventData { get; private set; } = default!; public DateTime CreationTime { get; private set; } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IAbpMongoDbContext.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IAbpMongoDbContext.cs index 12a76e9b00..5d47e2b39b 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IAbpMongoDbContext.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IAbpMongoDbContext.cs @@ -10,5 +10,5 @@ public interface IAbpMongoDbContext IMongoCollection Collection(); - IClientSessionHandle SessionHandle { get; } + IClientSessionHandle? SessionHandle { get; } } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoModelBuilder.cs index aa682412e6..9da7754bff 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoModelBuilder.cs @@ -6,9 +6,9 @@ namespace Volo.Abp.MongoDB; public interface IMongoModelBuilder { - void Entity(Action> buildAction = null); + void Entity(Action>? buildAction = null); - void Entity([NotNull] Type entityType, Action buildAction = null); + void Entity([NotNull] Type entityType, Action? buildAction = null); IReadOnlyList GetEntities(); } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoCollectionAttribute.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoCollectionAttribute.cs index b3f17472bd..9f12a39f26 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoCollectionAttribute.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoCollectionAttribute.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.MongoDB; public class MongoCollectionAttribute : Attribute { - public string CollectionName { get; set; } + public string? CollectionName { get; set; } public MongoCollectionAttribute() { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs index 306a03cf12..287f3ced0e 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs @@ -74,15 +74,15 @@ public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ISingleton return GetMongoQueryable(queryable).FirstAsync(predicate, cancellationToken); } - public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { - return GetMongoQueryable(queryable).FirstOrDefaultAsync(cancellationToken); + return GetMongoQueryable(queryable).FirstOrDefaultAsync(cancellationToken)!; } - public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { - return GetMongoQueryable(queryable).FirstOrDefaultAsync(predicate, cancellationToken); + return GetMongoQueryable(queryable).FirstOrDefaultAsync(predicate, cancellationToken)!; } public Task LastAsync(IQueryable queryable, CancellationToken cancellationToken = default) @@ -95,15 +95,15 @@ public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ISingleton return Task.FromResult(GetMongoQueryable(queryable).Last(predicate)); } - public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { - return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault()); + return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault()); } - public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { - return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault(predicate)); + return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault(predicate)); } public Task SingleAsync(IQueryable queryable, CancellationToken cancellationToken = default) @@ -116,15 +116,15 @@ public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ISingleton return GetMongoQueryable(queryable).SingleAsync(predicate, cancellationToken); } - public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) + public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) { - return GetMongoQueryable(queryable).SingleOrDefaultAsync(cancellationToken); + return GetMongoQueryable(queryable).SingleOrDefaultAsync(cancellationToken)!; } - public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, + public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) { - return GetMongoQueryable(queryable).SingleOrDefaultAsync(predicate, cancellationToken); + return GetMongoQueryable(queryable).SingleOrDefaultAsync(predicate, cancellationToken)!; } public Task MinAsync(IQueryable queryable, CancellationToken cancellationToken = default) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs index 12d0e72b44..e012e89072 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoEntityModelBuilder.cs @@ -11,7 +11,7 @@ public class MongoEntityModelBuilder : { public Type EntityType { get; } - public string CollectionName { get; set; } + public string CollectionName { get; set; } = default!; BsonClassMap IMongoEntityModelBuilder.BsonMap => _bsonClassMap; BsonClassMap IMongoEntityModelBuilder.BsonMap => _bsonClassMap; diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs index b0c936dbe2..b7de3043ac 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs @@ -121,7 +121,7 @@ public class MongoModelBuilder : IMongoModelBuilder return dbContext.LazyServiceProvider.LazyGetRequiredService>().Value.Kind; } - public virtual void Entity(Action> buildAction = null) + public virtual void Entity(Action>? buildAction = null) { var model = (IMongoEntityModelBuilder)_entityModelBuilders.GetOrAdd( typeof(TEntity), @@ -131,7 +131,7 @@ public class MongoModelBuilder : IMongoModelBuilder buildAction?.Invoke(model); } - public virtual void Entity(Type entityType, Action buildAction = null) + public virtual void Entity(Type entityType, Action? buildAction = null) { Check.NotNull(entityType, nameof(entityType)); @@ -139,7 +139,7 @@ public class MongoModelBuilder : IMongoModelBuilder entityType, () => (IMongoEntityModelBuilder)Activator.CreateInstance( typeof(MongoEntityModelBuilder<>).MakeGenericType(entityType) - ) + )! ); buildAction?.Invoke(model); diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs index 7048d183c7..6a2ab27870 100644 --- a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs @@ -1,5 +1,11 @@ using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; using Volo.Abp.DependencyInjection; namespace Volo.Abp.ObjectMapping; @@ -19,6 +25,8 @@ public class DefaultObjectMapper : DefaultObjectMapper, IObjectMapper< public class DefaultObjectMapper : IObjectMapper, ITransientDependency { + protected static ConcurrentDictionary MethodInfoCache { get; } = new ConcurrentDictionary(); + public IAutoObjectMappingProvider AutoObjectMappingProvider { get; } protected IServiceProvider ServiceProvider { get; } @@ -46,6 +54,12 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency { return specificMapper.Map(source); } + + var result = TryToMapCollection(scope, source, default); + if (result != null) + { + return result; + } } if (source is IMapTo mapperSource) @@ -85,6 +99,12 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency { return specificMapper.Map(source, destination); } + + var result = TryToMapCollection(scope, source, destination); + if (result != null) + { + return result; + } } if (source is IMapTo mapperSource) @@ -102,6 +122,131 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency return AutoMap(source, destination); } + protected virtual TDestination? TryToMapCollection(IServiceScope serviceScope, TSource source, TDestination? destination) + { + if (!IsCollectionGenericType(out var sourceArgumentType, out var destinationArgumentType, out var definitionGenericType)) + { + return default; + } + + var mapperType = typeof(IObjectMapper<,>).MakeGenericType(sourceArgumentType, destinationArgumentType); + var specificMapper = serviceScope.ServiceProvider.GetService(mapperType); + if (specificMapper == null) + { + //skip, no specific mapper + return default; + } + + var cacheKey = $"{mapperType.FullName}_{(destination == null ? "MapMethodWithSingleParameter" : "MapMethodWithDoubleParameters")}"; + var method = MethodInfoCache.GetOrAdd( + cacheKey, + _ => + { + return specificMapper + .GetType() + .GetMethods() + .First(x => + x.Name == nameof(IObjectMapper.Map) && + x.GetParameters().Length == (destination == null ? 1 : 2) + ); + } + ); + + var sourceList = source!.As(); + var result = definitionGenericType.IsGenericType + ? Activator.CreateInstance(definitionGenericType.MakeGenericType(destinationArgumentType))!.As() + : Array.CreateInstance(destinationArgumentType, sourceList.Count); + + if (destination != null && !destination.GetType().IsArray) + { + //Clear destination collection if destination not an array, We won't change array just same behavior as AutoMapper. + destination.As().Clear(); + } + + for (var i = 0; i < sourceList.Count; i++) + { + var invokeResult = destination == null + ? method.Invoke(specificMapper, new [] { sourceList[i] })! + : method.Invoke(specificMapper, new [] { sourceList[i], Activator.CreateInstance(destinationArgumentType)! })!; + + if (definitionGenericType.IsGenericType) + { + result.Add(invokeResult); + destination?.As().Add(invokeResult); + } + else + { + result[i] = invokeResult; + } + } + + if (destination != null && destination.GetType().IsArray) + { + //Return the new collection if destination is an array, We won't change array just same behavior as AutoMapper. + return (TDestination)result; + } + + //Return the destination if destination exists. The parameter reference equals with return object. + return destination ?? (TDestination)result; + } + + protected virtual bool IsCollectionGenericType(out Type sourceArgumentType, out Type destinationArgumentType, out Type definitionGenericType) + { + sourceArgumentType = default!; + destinationArgumentType = default!; + definitionGenericType = default!; + + if ((!typeof(TSource).IsGenericType && !typeof(TSource).IsArray) || + (!typeof(TDestination).IsGenericType && !typeof(TDestination).IsArray)) + { + return false; + } + + var supportedCollectionTypes = new[] + { + typeof(IEnumerable<>), + typeof(ICollection<>), + typeof(Collection<>), + typeof(IList<>), + typeof(List<>) + }; + + if (typeof(TSource).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TSource).GetGenericTypeDefinition())) + { + sourceArgumentType = typeof(TSource).GenericTypeArguments[0]; + } + + if (typeof(TSource).IsArray) + { + sourceArgumentType = typeof(TSource).GetElementType()!; + } + + if (sourceArgumentType == default!) + { + return false; + } + + definitionGenericType = typeof(List<>); + if (typeof(TDestination).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TDestination).GetGenericTypeDefinition())) + { + destinationArgumentType = typeof(TDestination).GenericTypeArguments[0]; + + if (typeof(TDestination).GetGenericTypeDefinition() == typeof(ICollection<>) || + typeof(TDestination).GetGenericTypeDefinition() == typeof(Collection<>)) + { + definitionGenericType = typeof(Collection<>); + } + } + + if (typeof(TDestination).IsArray) + { + destinationArgumentType = typeof(TDestination).GetElementType()!; + definitionGenericType = typeof(Array); + } + + return destinationArgumentType != default!; + } + protected virtual TDestination AutoMap(object source) { return AutoObjectMappingProvider.Map(source); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo.Abp.TextTemplating.Core.csproj b/framework/src/Volo.Abp.TextTemplating.Core/Volo.Abp.TextTemplating.Core.csproj index 8581d01dc4..f405dfe00c 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo.Abp.TextTemplating.Core.csproj +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo.Abp.TextTemplating.Core.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs index 43cc829010..6e17d6701a 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs @@ -25,9 +25,9 @@ public class AbpTemplateRenderer : ITemplateRenderer, ITransientDependency public virtual async Task RenderAsync( string templateName, - object model = null, - string cultureName = null, - Dictionary globalContext = null) + object? model = null, + string? cultureName = null, + Dictionary? globalContext = null) { var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); @@ -38,7 +38,7 @@ public class AbpTemplateRenderer : ITemplateRenderer, ITransientDependency renderEngine = Options.DefaultRenderingEngine; } - var providerType = Options.RenderingEngines.GetOrDefault(renderEngine); + var providerType = Options.RenderingEngines.GetOrDefault(renderEngine!); if (providerType != null && typeof(ITemplateRenderingEngine).IsAssignableFrom(providerType)) { diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs index 28b2e28ad0..40dac35703 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs @@ -10,7 +10,7 @@ public class AbpTextTemplatingOptions public ITypeList ContentContributors { get; } public IDictionary RenderingEngines { get; } - public string DefaultRenderingEngine { get; set; } + public string? DefaultRenderingEngine { get; set; } public HashSet DeletedTemplates { get; } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs index e275eb39be..205cae5824 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs @@ -10,5 +10,5 @@ public interface IDynamicTemplateDefinitionStore Task> GetAllAsync(); - Task GetOrNullAsync(string name); + Task GetOrNullAsync(string name); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs index d298a42541..6e6d763616 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs @@ -10,5 +10,5 @@ public interface IStaticTemplateDefinitionStore Task> GetAllAsync(); - Task GetOrNullAsync(string name); + Task GetOrNullAsync(string name); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentContributor.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentContributor.cs index fadd8696a8..086644db98 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentContributor.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentContributor.cs @@ -4,5 +4,5 @@ namespace Volo.Abp.TextTemplating; public interface ITemplateContentContributor { - Task GetOrNullAsync(TemplateContentContributorContext context); + Task GetOrNullAsync(TemplateContentContributorContext context); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentProvider.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentProvider.cs index ac944946c0..1fe3f25d5f 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateContentProvider.cs @@ -5,16 +5,16 @@ namespace Volo.Abp.TextTemplating; public interface ITemplateContentProvider { - Task GetContentOrNullAsync( + Task GetContentOrNullAsync( [NotNull] string templateName, - [CanBeNull] string cultureName = null, + string? cultureName = null, bool tryDefaults = true, bool useCurrentCultureIfCultureNameIsNull = true ); - Task GetContentOrNullAsync( + Task GetContentOrNullAsync( [NotNull] TemplateDefinition templateDefinition, - [CanBeNull] string cultureName = null, + string? cultureName = null, bool tryDefaults = true, bool useCurrentCultureIfCultureNameIsNull = true ); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs index f2caa3c805..fd219ea23c 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionContext.cs @@ -6,7 +6,7 @@ public interface ITemplateDefinitionContext { IReadOnlyList GetAll(); - TemplateDefinition GetOrNull(string name); + TemplateDefinition? GetOrNull(string name); void Add(params TemplateDefinition[] definitions); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs index fa20673cea..b8903db522 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs @@ -12,6 +12,5 @@ public interface ITemplateDefinitionManager [ItemNotNull] Task> GetAllAsync(); - [ItemCanBeNull] - Task GetOrNullAsync(string name); + Task GetOrNullAsync(string name); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderer.cs index 62e17f69a8..324984d44b 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderer.cs @@ -17,8 +17,8 @@ public interface ITemplateRenderer /// Task RenderAsync( [NotNull] string templateName, - [CanBeNull] object model = null, - [CanBeNull] string cultureName = null, - [CanBeNull] Dictionary globalContext = null + object? model = null, + string? cultureName = null, + Dictionary? globalContext = null ); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderingEngine.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderingEngine.cs index da080ffdb3..e100825011 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderingEngine.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateRenderingEngine.cs @@ -19,8 +19,8 @@ public interface ITemplateRenderingEngine /// Task RenderAsync( [NotNull] string templateName, - [CanBeNull] object model = null, - [CanBeNull] string cultureName = null, - [CanBeNull] Dictionary globalContext = null + object? model = null, + string? cultureName = null, + Dictionary? globalContext = null ); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs index 115f46b2ac..5c72c6e7c4 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs @@ -8,13 +8,13 @@ namespace Volo.Abp.TextTemplating; public class NullIDynamicTemplateDefinitionStore : IDynamicTemplateDefinitionStore, ISingletonDependency { - private readonly static Task CachedTemplateResult = Task.FromResult((TemplateDefinition)null); + private readonly static Task CachedTemplateResult = Task.FromResult((TemplateDefinition?)null); private readonly static Task> CachedTemplatesResult = Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); public Task GetAsync(string name) { - return CachedTemplateResult; + return CachedTemplateResult!; } public Task> GetAllAsync() @@ -22,7 +22,7 @@ public class NullIDynamicTemplateDefinitionStore : IDynamicTemplateDefinitionSto return CachedTemplatesResult; } - public Task GetOrNullAsync(string name) + public Task GetOrNullAsync(string name) { return CachedTemplateResult; } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs index d12db86da8..4231f39b4d 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs @@ -36,7 +36,7 @@ public class StaticTemplateDefinitionStore : IStaticTemplateDefinitionStore, ISi throw new AbpException("Undefined template: " + name); } - return template; + return template!; } public virtual Task> GetAllAsync() @@ -44,7 +44,7 @@ public class StaticTemplateDefinitionStore : IStaticTemplateDefinitionStore, ISi return Task.FromResult>(TemplateDefinitions.Value.Values.ToImmutableList()); } - public virtual Task GetOrNullAsync(string name) + public virtual Task GetOrNullAsync(string name) { return Task.FromResult(TemplateDefinitions.Value.GetOrDefault(name)); } @@ -57,7 +57,7 @@ public class StaticTemplateDefinitionStore : IStaticTemplateDefinitionStore, ISi { var providers = Options .DefinitionProviders - .Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider) + .Select(p => (scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider)!) .ToList(); var context = new TemplateDefinitionContext(templates); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs index 11b9af255a..8ea941114a 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentContributorContext.cs @@ -11,13 +11,12 @@ public class TemplateContentContributorContext [NotNull] public IServiceProvider ServiceProvider { get; } - [CanBeNull] - public string Culture { get; } + public string? Culture { get; } public TemplateContentContributorContext( [NotNull] TemplateDefinition templateDefinition, [NotNull] IServiceProvider serviceProvider, - [CanBeNull] string culture) + string? culture) { TemplateDefinition = Check.NotNull(templateDefinition, nameof(templateDefinition)); ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider)); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs index 64ecd1f4c7..5c9a51be82 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs @@ -26,9 +26,9 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen _templateDefinitionManager = templateDefinitionManager; } - public virtual async Task GetContentOrNullAsync( + public virtual async Task GetContentOrNullAsync( [NotNull] string templateName, - [CanBeNull] string cultureName = null, + string? cultureName = null, bool tryDefaults = true, bool useCurrentCultureIfCultureNameIsNull = true) { @@ -36,9 +36,9 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen return await GetContentOrNullAsync(template, cultureName); } - public virtual async Task GetContentOrNullAsync( + public virtual async Task GetContentOrNullAsync( [NotNull] TemplateDefinition templateDefinition, - [CanBeNull] string cultureName = null, + string? cultureName = null, bool tryDefaults = true, bool useCurrentCultureIfCultureNameIsNull = true) { @@ -53,7 +53,7 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen using (var scope = ServiceScopeFactory.CreateScope()) { - string templateString = null; + string? templateString = null; if (cultureName == null && useCurrentCultureIfCultureNameIsNull) { @@ -151,7 +151,7 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen .ToArray(); } - protected virtual async Task GetContentOrNullAsync( + protected virtual async Task GetContentOrNullAsync( ITemplateContentContributor[] contributors, TemplateContentContributorContext context) { diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs index 64aeba815e..a371fc3a9a 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs @@ -20,23 +20,19 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName _displayName = value; } } - private ILocalizableString _displayName; + private ILocalizableString _displayName = default!; public bool IsLayout { get; } - [CanBeNull] - public string Layout { get; set; } + public string? Layout { get; set; } - [CanBeNull] - public string LocalizationResourceName { get; set; } + public string? LocalizationResourceName { get; set; } public bool IsInlineLocalized { get; set; } - [CanBeNull] - public string DefaultCultureName { get; } + public string? DefaultCultureName { get; } - [CanBeNull] - public string RenderEngine { get; set; } + public string? RenderEngine { get; set; } /// /// Gets/sets a key-value on the . @@ -46,8 +42,7 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName /// Returns the value in the dictionary by given . /// Returns null if given is not present in the dictionary. /// - [CanBeNull] - public object this[string name] { + public object? this[string name] { get => Properties.GetOrDefault(name); set => Properties[name] = value; } @@ -56,15 +51,15 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName /// Can be used to get/set custom properties for this feature. /// [NotNull] - public Dictionary Properties { get; } + public Dictionary Properties { get; } public TemplateDefinition( [NotNull] string name, [NotNull] Type localizationResource, - [CanBeNull] ILocalizableString displayName = null, + ILocalizableString? displayName = null, bool isLayout = false, - string layout = null, - string defaultCultureName = null) + string? layout = null, + string? defaultCultureName = null) : this(name, LocalizationResourceNameAttribute.GetName(localizationResource), displayName, isLayout, layout, defaultCultureName) { @@ -72,11 +67,11 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName public TemplateDefinition( [NotNull] string name, - [CanBeNull] string localizationResourceName = null, - [CanBeNull] ILocalizableString displayName = null, + string? localizationResourceName = null, + ILocalizableString? displayName = null, bool isLayout = false, - string layout = null, - string defaultCultureName = null) + string? layout = null, + string? defaultCultureName = null) { Name = Check.NotNullOrWhiteSpace(name, nameof(name), MaxNameLength); LocalizationResourceName = localizationResourceName; @@ -84,7 +79,7 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName IsLayout = isLayout; Layout = layout; DefaultCultureName = defaultCultureName; - Properties = new Dictionary(); + Properties = new Dictionary(); } /// diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs index b32332807f..9edd370ecf 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionContext.cs @@ -17,7 +17,7 @@ public class TemplateDefinitionContext : ITemplateDefinitionContext return Templates.Values.ToImmutableList(); } - public virtual TemplateDefinition GetOrNull(string name) + public virtual TemplateDefinition? GetOrNull(string name) { return Templates.GetOrDefault(name); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs index 35cc69275d..0d830e65ef 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionExtensions.cs @@ -21,7 +21,7 @@ public static class TemplateDefinitionExtensions ); } - public static string GetVirtualFilePathOrNull( + public static string? GetVirtualFilePathOrNull( [NotNull] this TemplateDefinition templateDefinition) { Check.NotNull(templateDefinition, nameof(templateDefinition)); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs index 7e2920e446..32d4d8eeab 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs @@ -28,7 +28,7 @@ public class TemplateDefinitionManager : ITemplateDefinitionManager, ISingletonD return permission; } - public virtual async Task GetOrNullAsync(string name) + public virtual async Task GetOrNullAsync(string name) { Check.NotNull(name, nameof(name)); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs index a2c354801d..62c8dee43c 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs @@ -22,14 +22,14 @@ public abstract class TemplateRenderingEngineBase : ITemplateRenderingEngine StringLocalizerFactory = stringLocalizerFactory; } - public abstract Task RenderAsync(string templateName, object model = null, string cultureName = null, Dictionary globalContext = null); + public abstract Task RenderAsync(string templateName, object? model = null, string? cultureName = null, Dictionary? globalContext = null); - protected virtual async Task GetContentOrNullAsync(TemplateDefinition templateDefinition) + protected virtual async Task GetContentOrNullAsync(TemplateDefinition templateDefinition) { return await TemplateContentProvider.GetContentOrNullAsync(templateDefinition); } - protected virtual IStringLocalizer GetLocalizerOrNull(TemplateDefinition templateDefinition) + protected virtual IStringLocalizer? GetLocalizerOrNull(TemplateDefinition templateDefinition) { if (templateDefinition.LocalizationResourceName != null) { diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs index 27e400c082..81074936e6 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs @@ -5,8 +5,8 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentReader { - private IFileInfo _fileInfo; - private string _content; + private IFileInfo _fileInfo = default!; + private string _content = default!; public async Task ReadContentsAsync(IFileInfo fileInfo) { @@ -14,7 +14,7 @@ public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentR _content = await fileInfo.ReadAsStringAsync(); } - public string GetContentOrNull(string culture) + public string? GetContentOrNull(string? culture) { if (culture == null) { diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs index 9fc15d1954..ab2380c069 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/ILocalizedTemplateContentReader.cs @@ -4,5 +4,5 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public interface ILocalizedTemplateContentReader { - public string GetContentOrNull([CanBeNull] string culture); + public string? GetContentOrNull(string? culture); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs index 878428b5ef..f2988d8197 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/NullLocalizedTemplateContentReader.cs @@ -9,7 +9,7 @@ public class NullLocalizedTemplateContentReader : ILocalizedTemplateContentReade } - public string GetContentOrNull(string culture) + public string? GetContentOrNull(string? culture) { return null; } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs index 5469700432..45dbd6e553 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs @@ -2,7 +2,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public class TemplateContentFileInfo { - public string FileName { get; set; } + public string FileName { get; set; } = default!; - public string FileContent { get; set; } + public string FileContent { get; set; } = default!; } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs index 7bd66f2f50..999bc62de9 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContentContributor.cs @@ -15,7 +15,7 @@ public class VirtualFileTemplateContentContributor : ITemplateContentContributor _localizedTemplateContentReaderFactory = localizedTemplateContentReaderFactory; } - public virtual async Task GetOrNullAsync(TemplateContentContributorContext context) + public virtual async Task GetOrNullAsync(TemplateContentContributorContext context) { var localizedReader = await _localizedTemplateContentReaderFactory .CreateAsync(context.TemplateDefinition); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs index 828978b1d2..0e6c9b13c2 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateContentReader { - private Dictionary _dictionary; + private Dictionary _dictionary = default!; private readonly string[] _fileExtension; public VirtualFolderLocalizedTemplateContentReader(string[] fileExtension) @@ -44,7 +44,7 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon } } - public string GetContentOrNull(string cultureName) + public string? GetContentOrNull(string? cultureName) { if (cultureName == null) { diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj b/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj index 962746bd0a..4242ca9f29 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo.Abp.TextTemplating.Razor.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs index c1dc5005b1..bdc8897ddf 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/AbpRazorTemplateCSharpCompiler.cs @@ -40,7 +40,7 @@ public class AbpRazorTemplateCSharpCompiler : ISingletonDependency .Select(x => MetadataReference.CreateFromFile(x.Location)) .ToImmutableList(); - public virtual Stream CreateAssembly(string code, string assemblyName, List references = null, CSharpCompilationOptions options = null) + public virtual Stream CreateAssembly(string code, string assemblyName, List? references = null, CSharpCompilationOptions? options = null) { var defaultReferences = DefaultReferences.Concat(Options.References); try diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs index d15d70ded6..d17bfaea4f 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpRazorProjectEngineFactory.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.TextTemplating.Razor; public class DefaultAbpRazorProjectEngineFactory : IAbpRazorProjectEngineFactory, ITransientDependency { - public virtual async Task CreateAsync(Action configure = null) + public virtual async Task CreateAsync(Action? configure = null) { return RazorProjectEngine.Create(await CreateRazorConfigurationAsync(), EmptyProjectFileSystem.Empty, configure); } diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs index fd2b90a6b1..8c8d8703dd 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/EmptyProjectFileSystem.cs @@ -21,7 +21,7 @@ internal class EmptyProjectFileSystem : RazorProjectFileSystem return GetItem(path, fileKind: null); } - public override RazorProjectItem GetItem(string path, string fileKind) + public override RazorProjectItem GetItem(string path, string? fileKind) { NormalizeAndEnsureValidPath(path); return new NotFoundProjectItem(string.Empty, path, fileKind); diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs index 969ce762d1..197133ef72 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IAbpRazorProjectEngineFactory.cs @@ -6,5 +6,5 @@ namespace Volo.Abp.TextTemplating.Razor; public interface IAbpRazorProjectEngineFactory { - Task CreateAsync(Action configure = null); + Task CreateAsync(Action? configure = null); } diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs index 78b80941e9..f4b2a17006 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/IRazorTemplatePage.cs @@ -8,24 +8,24 @@ namespace Volo.Abp.TextTemplating.Razor; public interface IRazorTemplatePage : IRazorTemplatePage { - TModel Model { get; set; } + TModel? Model { get; set; } } public interface IRazorTemplatePage { IServiceProvider ServiceProvider { get; set; } - IStringLocalizer Localizer { get; set; } + IStringLocalizer? Localizer { get; set; } - HtmlEncoder HtmlEncoder { get; set; } + HtmlEncoder? HtmlEncoder { get; set; } - JavaScriptEncoder JavaScriptEncoder { get; set; } + JavaScriptEncoder? JavaScriptEncoder { get; set; } - UrlEncoder UrlEncoder { get; set; } + UrlEncoder? UrlEncoder { get; set; } Dictionary GlobalContext { get; set; } - string Body { get; set; } + string? Body { get; set; } Task ExecuteAsync(); diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs index 5db2c8f582..2651237d2d 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/NotFoundProjectItem.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.TextTemplating.Razor; internal class NotFoundProjectItem : RazorProjectItem { - public NotFoundProjectItem(string basePath, string path, string fileKind) + public NotFoundProjectItem(string basePath, string path, string? fileKind) { BasePath = basePath; FilePath = path; diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs index fd2d2c13e7..a85d9d1480 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplatePageBase.cs @@ -9,30 +9,30 @@ namespace Volo.Abp.TextTemplating.Razor; public abstract class RazorTemplatePageBase : RazorTemplatePageBase, IRazorTemplatePage { - public TModel Model { get; set; } + public TModel? Model { get; set; } } public abstract class RazorTemplatePageBase : IRazorTemplatePage { - public Dictionary GlobalContext { get; set; } + public Dictionary GlobalContext { get; set; } = default!; - public IServiceProvider ServiceProvider { get; set; } + public IServiceProvider ServiceProvider { get; set; } = default!; - public IStringLocalizer Localizer { get; set; } + public IStringLocalizer? Localizer { get; set; } - public HtmlEncoder HtmlEncoder { get; set; } + public HtmlEncoder? HtmlEncoder { get; set; } - public JavaScriptEncoder JavaScriptEncoder { get; set; } + public JavaScriptEncoder? JavaScriptEncoder { get; set; } - public UrlEncoder UrlEncoder { get; set; } + public UrlEncoder? UrlEncoder { get; set; } - public string Body { get; set; } + public string? Body { get; set; } private readonly StringBuilder _stringBuilder = new StringBuilder(); private AttributeInfo _attributeInfo; - public virtual void WriteLiteral(string literal = null) + public virtual void WriteLiteral(string? literal = null) { if (!literal.IsNullOrEmpty()) { @@ -40,7 +40,7 @@ public abstract class RazorTemplatePageBase : IRazorTemplatePage } } - public virtual void Write(object value = null) + public virtual void Write(object? value = null) { if (value is null) { diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs index 86298f2daf..2384bd8740 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs @@ -34,9 +34,9 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi public override async Task RenderAsync( [NotNull] string templateName, - [CanBeNull] object model = null, - [CanBeNull] string cultureName = null, - [CanBeNull] Dictionary globalContext = null) + object? model = null, + string? cultureName = null, + Dictionary? globalContext = null) { Check.NotNullOrWhiteSpace(templateName, nameof(templateName)); @@ -70,9 +70,9 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi protected virtual async Task RenderInternalAsync( string templateName, - string body, + string? body, Dictionary globalContext, - object model = null) + object? model = null) { var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); @@ -97,9 +97,9 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi protected virtual async Task RenderSingleTemplateAsync( TemplateDefinition templateDefinition, - string body, + string? body, Dictionary globalContext, - object model = null) + object? model = null) { return await RenderTemplateContentWithRazorAsync( templateDefinition, @@ -111,13 +111,13 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi protected virtual async Task RenderTemplateContentWithRazorAsync( TemplateDefinition templateDefinition, - string body, + string? body, Dictionary globalContext, - object model = null) + object? model = null) { var assembly = await AbpCompiledViewProvider.GetAssemblyAsync(templateDefinition); - var templateType = assembly.GetType(AbpRazorTemplateConsts.TypeName); - var template = (IRazorTemplatePage)Activator.CreateInstance(templateType); + var templateType = assembly.GetType(AbpRazorTemplateConsts.TypeName)!; + var template = (IRazorTemplatePage)Activator.CreateInstance(templateType)!; using (var scope = ServiceScopeFactory.CreateScope()) { @@ -147,11 +147,11 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi } } - private void SetModel(IRazorTemplatePage razorTemplatePage, object model = null) + private void SetModel(IRazorTemplatePage razorTemplatePage, object? model = null) { if (razorTemplatePage is IRazorTemplatePage razorTemplatePageWithModel) { - razorTemplatePageWithModel.Model = (TModel)model; + razorTemplatePageWithModel.Model = (TModel?)model; } } } diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj index d18d90c8f9..ea1d0f0f8d 100644 --- a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo.Abp.TextTemplating.Scriban.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs index 91af004cf9..6bf32d1a58 100644 --- a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateLocalizer.cs @@ -44,7 +44,7 @@ public class ScribanTemplateLocalizer : IScriptCustomFunction } var args = arguments.Skip(1).Where(x => x != null && !x.ToString().IsNullOrWhiteSpace()).ToArray(); - return args.Any() ? _localizer[name.ToString(), args] : _localizer[name.ToString()]; + return args.Any() ? _localizer[name.ToString()!, args] : _localizer[name.ToString()!]; } public int RequiredParameterCount => 1; diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs index a4da669893..7a5ac79592 100644 --- a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs @@ -24,9 +24,9 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran public override async Task RenderAsync( [NotNull] string templateName, - [CanBeNull] object model = null, - [CanBeNull] string cultureName = null, - [CanBeNull] Dictionary globalContext = null) + object? model = null, + string? cultureName = null, + Dictionary? globalContext = null) { Check.NotNullOrWhiteSpace(templateName, nameof(templateName)); @@ -59,7 +59,7 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran protected virtual async Task RenderInternalAsync( string templateName, Dictionary globalContext, - object model = null) + object? model = null) { var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); @@ -84,13 +84,13 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran protected virtual async Task RenderSingleTemplateAsync( TemplateDefinition templateDefinition, Dictionary globalContext, - object model = null) + object? model = null) { var rawTemplateContent = await GetContentOrNullAsync(templateDefinition); return await RenderTemplateContentWithScribanAsync( templateDefinition, - rawTemplateContent, + rawTemplateContent!, globalContext, model ); @@ -100,7 +100,7 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran TemplateDefinition templateDefinition, string templateContent, Dictionary globalContext, - object model = null) + object? model = null) { var context = CreateScribanTemplateContext( templateDefinition, @@ -116,7 +116,7 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran protected virtual TemplateContext CreateScribanTemplateContext( TemplateDefinition templateDefinition, Dictionary globalContext, - object model = null) + object? model = null) { var context = new TemplateContext(); diff --git a/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj b/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj index 27907183c0..f8d1d85192 100644 --- a/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj +++ b/framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj @@ -5,6 +5,8 @@ netstandard2.0;netstandard2.1;net7.0 + enable + Nullable diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs index eb51d8c189..5f400abcfd 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -10,7 +10,7 @@ internal class ChildUnitOfWork : IUnitOfWork { public Guid Id => _parent.Id; - public IAbpUnitOfWorkOptions? Options => _parent.Options; + public IAbpUnitOfWorkOptions Options => _parent.Options; public IUnitOfWork? Outer => _parent.Outer; diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs index 15dc2bdec0..4ebc5afd84 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs @@ -17,7 +17,7 @@ public interface IUnitOfWork : IDatabaseApiContainer, ITransactionApiContainer, event EventHandler Disposed; - IAbpUnitOfWorkOptions? Options { get; } + IAbpUnitOfWorkOptions Options { get; } IUnitOfWork? Outer { get; } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index c04393d104..74b1b79e77 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -21,7 +21,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency public Guid Id { get; } = Guid.NewGuid(); - public IAbpUnitOfWorkOptions? Options { get; private set; } + public IAbpUnitOfWorkOptions Options { get; private set; } = default!; public IUnitOfWork? Outer { get; private set; } diff --git a/framework/test/AbpTestBase/Microsoft/Extensions/DependencyInjection/ServiceCollectionShouldlyExtensions.cs b/framework/test/AbpTestBase/Microsoft/Extensions/DependencyInjection/ServiceCollectionShouldlyExtensions.cs index 6c3f8e5090..541b62f58d 100644 --- a/framework/test/AbpTestBase/Microsoft/Extensions/DependencyInjection/ServiceCollectionShouldlyExtensions.cs +++ b/framework/test/AbpTestBase/Microsoft/Extensions/DependencyInjection/ServiceCollectionShouldlyExtensions.cs @@ -17,6 +17,17 @@ public static class ServiceCollectionShouldlyExtensions serviceDescriptor.Lifetime.ShouldBe(ServiceLifetime.Transient); } + public static void ShouldContainTransientImplementationFactory(this IServiceCollection services, Type serviceType) + { + var serviceDescriptor = services.FirstOrDefault(s => s.ServiceType == serviceType); + + serviceDescriptor.ShouldNotBeNull(); + serviceDescriptor.ImplementationType.ShouldBeNull(); + serviceDescriptor.ImplementationFactory.ShouldNotBeNull(); + serviceDescriptor.ImplementationInstance.ShouldBeNull(); + serviceDescriptor.Lifetime.ShouldBe(ServiceLifetime.Transient); + } + public static void ShouldContainSingleton(this IServiceCollection services, Type serviceType, Type implementationType = null) { var serviceDescriptor = services.FirstOrDefault(s => s.ServiceType == serviceType); diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Program.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Program.cs new file mode 100644 index 0000000000..d2e28ce2c1 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.App; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Startup.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Startup.cs deleted file mode 100644 index 46981d27be..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/Startup.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.App; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancyTestBase.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancyTestBase.cs index 15991117f4..7ff1acc7a5 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancyTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancyTestBase.cs @@ -1,7 +1,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy; -public abstract class AspNetCoreMultiTenancyTestBase : AbpAspNetCoreTestBase +public abstract class AspNetCoreMultiTenancyTestBase : AbpAspNetCoreTestBase { } diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs index a630df4986..e80b47b2a5 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs @@ -24,23 +24,22 @@ public class AspNetCoreMultiTenancy_WithDomainResolver_Tests : AspNetCoreMultiTe _options = ServiceProvider.GetRequiredService>().Value; } - protected override IHostBuilder CreateHostBuilder() + protected override void ConfigureServices(IServiceCollection services) { - return base.CreateHostBuilder().ConfigureServices(services => + services.Configure(options => { - services.Configure(options => + options.Tenants = new[] { - options.Tenants = new[] - { - new TenantConfiguration(_testTenantId, _testTenantName) - }; - }); + new TenantConfiguration(_testTenantId, _testTenantName) + }; + }); - services.Configure(options => - { - options.AddDomainTenantResolver("{0}.abp.io:8080"); - }); + services.Configure(options => + { + options.AddDomainTenantResolver("{0}.abp.io:8080"); }); + + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs index ccbd941bae..56da287ef8 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs @@ -25,18 +25,17 @@ public class AspNetCoreMultiTenancy_Without_DomainResolver_Tests : AspNetCoreMul _options = ServiceProvider.GetRequiredService>().Value; } - protected override IHostBuilder CreateHostBuilder() + protected override void ConfigureServices(IServiceCollection services) { - return base.CreateHostBuilder().ConfigureServices(services => + services.Configure(options => { - services.Configure(options => + options.Tenants = new[] { - options.Tenants = new[] - { - new TenantConfiguration(_testTenantId, _testTenantName) - }; - }); + new TenantConfiguration(_testTenantId, _testTenantName) + }; }); + + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs index 6acbb77242..d1e02f8ebc 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs @@ -1,41 +1,6 @@ -using System.IO; -using System.Linq; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - namespace Volo.Abp.AspNetCore.Mvc; -public abstract class AspNetCoreMvcTestBase : AbpAspNetCoreTestBase +public abstract class AspNetCoreMvcTestBase : AbpAspNetCoreTestBase { - protected override IHostBuilder CreateHostBuilder() - { - var contentRootPath = CalculateContentRootPath( - "Volo.Abp.AspNetCore.Mvc.Tests.csproj", - string.Format( - "Volo{0}Abp{0}AspNetCore{0}App", - Path.DirectorySeparatorChar - ) - ); - - return base.CreateHostBuilder() - .UseContentRoot(contentRootPath); - } - - private static string CalculateContentRootPath(string projectFileName, string contentPath) - { - var currentDirectory = Directory.GetCurrentDirectory(); - while (!ContainsFile(currentDirectory, projectFileName)) - { - currentDirectory = new DirectoryInfo(currentDirectory).Parent.FullName; - } - - return Path.Combine(currentDirectory, contentPath); - } - private static bool ContainsFile(string currentDirectory, string projectFileName) - { - return Directory - .GetFiles(currentDirectory, "*.*", SearchOption.TopDirectoryOnly) - .Any(f => Path.GetFileName(f) == projectFileName); - } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditIntegrationServiceTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditIntegrationServiceTestController_Tests.cs index 129035f406..74677b27c4 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditIntegrationServiceTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditIntegrationServiceTestController_Tests.cs @@ -22,11 +22,11 @@ public class AuditIntegrationServiceTestController_Tests : AspNetCoreMvcTestBase _auditingStore = ServiceProvider.GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { _auditingStore = Substitute.For(); services.Replace(ServiceDescriptor.Singleton(_auditingStore)); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] @@ -55,4 +55,4 @@ public class AuditIntegrationServiceTestController_Tests : AspNetCoreMvcTestBase await GetResponseAsync("/integration-api/audit-test/"); await _auditingStore.DidNotReceive().SaveAsync(Arg.Any()); } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs index 78d537e252..f818b6f987 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -23,11 +24,11 @@ public class AuditTestController_Tests : AspNetCoreMvcTestBase _auditingStore = ServiceProvider.GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { _auditingStore = Substitute.For(); services.Replace(ServiceDescriptor.Singleton(_auditingStore)); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] @@ -41,6 +42,23 @@ public class AuditTestController_Tests : AspNetCoreMvcTestBase x.Actions.Any(a => a.MethodName == nameof(AuditTestController.Get)))); } + + [Fact] + public async Task Should_Disable_AuditLog_For_Get_And_Head_Requests() + { + _options.IsEnabledForGetRequests = false; + await GetResponseAsync("api/audit-test/audit-success"); + await _auditingStore.Received().DidNotReceive().SaveAsync(Arg.Any()); + + using (var requestMessage = new HttpRequestMessage(HttpMethod.Head, "api/audit-test/audit-success")) + { + var response = await Client.SendAsync(requestMessage); + response.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK); + } + + await _auditingStore.Received().DidNotReceive().SaveAsync(Arg.Any()); + } + [Fact] public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_GetRequests() { @@ -50,7 +68,6 @@ public class AuditTestController_Tests : AspNetCoreMvcTestBase await _auditingStore.Received().SaveAsync(Arg.Any()); } - [Fact] public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_Specified_Requests() { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs index aae671d6d4..466072358a 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NSubstitute; +using Shouldly; using Volo.Abp.Auditing; using Xunit; @@ -22,11 +24,11 @@ public class AuditTestPage_Tests : AspNetCoreMvcTestBase _auditingStore = ServiceProvider.GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { _auditingStore = Substitute.For(); services.Replace(ServiceDescriptor.Singleton(_auditingStore)); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] @@ -40,6 +42,22 @@ public class AuditTestPage_Tests : AspNetCoreMvcTestBase x.Actions.Any(a => a.MethodName == nameof(AuditTestPage.OnGet)))); } + [Fact] + public async Task Should_Disable_AuditLog_For_Get_And_Head_Requests() + { + _options.IsEnabledForGetRequests = false; + await GetResponseAsync("/Auditing/AuditTestPage"); + await _auditingStore.Received().DidNotReceive().SaveAsync(Arg.Any()); + + using (var requestMessage = new HttpRequestMessage(HttpMethod.Head, "/Auditing/AuditTestPage")) + { + var response = await Client.SendAsync(requestMessage); + response.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK); + } + + await _auditingStore.Received().DidNotReceive().SaveAsync(Arg.Any()); + } + [Fact] public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_GetRequests() { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Controllers/ReplaceBuiltInController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Controllers/ReplaceBuiltInController_Tests.cs index 46aa0369e3..7060a91b99 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Controllers/ReplaceBuiltInController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Controllers/ReplaceBuiltInController_Tests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Controllers; public class ReplaceBuiltInController_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs index e8e49b4946..95e6b5ca47 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestController_Tests.cs @@ -24,9 +24,9 @@ public class AbpAuthorizationExceptionTestController_Tests : AspNetCoreMvcTestBa FakeRequiredService = GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { - base.ConfigureServices(context, services); + base.ConfigureServices(services); FakeExceptionSubscriber = Substitute.For(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs index 689f3a00dc..0b10ff91da 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpAuthorizationExceptionTestPage_Tests.cs @@ -24,9 +24,9 @@ public class AbpAuthorizationExceptionTestPage_Tests : AspNetCoreMvcTestBase _fakeRequiredService = GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { - base.ConfigureServices(context, services); + base.ConfigureServices(services); _fakeExceptionSubscriber = Substitute.For(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs index 2f10f4b027..1b79441de8 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs @@ -26,9 +26,9 @@ public class ExceptionTestController_Tests : AspNetCoreMvcTestBase FakeRequiredService = GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { - base.ConfigureServices(context, services); + base.ConfigureServices(services); _fakeExceptionSubscriber = Substitute.For(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs index 3290b37c95..48ccf6499f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestPage_Tests.cs @@ -26,9 +26,9 @@ public class ExceptionTestPage_Tests : AspNetCoreMvcTestBase _fakeRequiredService = GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { - base.ConfigureServices(context, services); + base.ConfigureServices(services); _fakeExceptionSubscriber = Substitute.For(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs index e7015313cb..23c16677e2 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs @@ -10,14 +10,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Json; public class JsonResultController_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { options.OutputDateTimeFormat = "yyyy*MM*dd"; }); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs index 1613e4bb49..d0888a0fdf 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs @@ -17,14 +17,14 @@ public class JsonSerializer_Tests : AspNetCoreMvcTestBase _jsonSerializer = ServiceProvider.GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { options.OutputDateTimeFormat = "yyyy*MM*dd"; }); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/LocalizationTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/LocalizationTestController_Tests.cs index b575b4ce78..d23a5c1a9f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/LocalizationTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/LocalizationTestController_Tests.cs @@ -21,7 +21,7 @@ public class LocalizationTestController_Tests : AspNetCoreMvcTestBase } } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index 53bfff8b68..973e2f7192 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -122,22 +122,22 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase public class ModelBindingController_Utc_Tests : ModelBindingController_Tests { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { Kind = DateTimeKind.Utc; services.Configure(x => x.Kind = Kind); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } } public class ModelBindingController_Local_Tests : ModelBindingController_Tests { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { Kind = DateTimeKind.Local; services.Configure(x => x.Kind = Kind); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Program.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Program.cs new file mode 100644 index 0000000000..9e1bf5e51c --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Program.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Modularity.PlugIns; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(options => +{ + var hostEnvironment = options.Services.GetHostingEnvironment(); + var currentDirectory = hostEnvironment.ContentRootPath; + var plugDllInPath = ""; + + for (var i = 0; i < 10; i++) + { + var parentDirectory = new DirectoryInfo(currentDirectory).Parent; + if (parentDirectory == null) + { + break; + } + + if (parentDirectory.Name == "test") + { +#if DEBUG + plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Debug", "net7.0"); +#else + plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Release", "net7.0"); +#endif + break; + } + + currentDirectory = parentDirectory.FullName; + } + + if (plugDllInPath.IsNullOrWhiteSpace()) + { + throw new AbpException("Could not find the plug DLL path!"); + } + + options.PlugInSources.AddFolder(plugDllInPath); +}); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs index 4c419ef744..dab4a03466 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Security.Headers; public class SecurityHeadersTestController_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { @@ -18,7 +18,7 @@ public class SecurityHeadersTestController_Tests : AspNetCoreMvcTestBase options.Headers["Referrer-Policy"] = "no-referrer"; }); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs deleted file mode 100644 index df5a8b7b9c..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Volo.Abp.Modularity.PlugIns; - -namespace Volo.Abp.AspNetCore.Mvc; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(options => - { - var hostEnvironment = services.GetHostingEnvironment(); - var currentDirectory = hostEnvironment.ContentRootPath; - var plugDllInPath = ""; - - for (var i = 0; i < 10; i++) - { - var parentDirectory = new DirectoryInfo(currentDirectory).Parent; - if (parentDirectory == null) - { - break; - } - - if (parentDirectory.Name == "test") - { -#if DEBUG - plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Debug", "net7.0"); -#else - plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Release", "net7.0"); -#endif - break; - } - - currentDirectory = parentDirectory.FullName; - } - - if (plugDllInPath.IsNullOrWhiteSpace()) - { - throw new AbpException("Could not find the plug DLL path!"); - } - - options.PlugInSources.AddFolder(plugDllInPath); - }); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs index 068accad6a..7c0658638d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs @@ -14,7 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow; public class UnitOfWorkMiddleware_Exception_Rollback_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Replace(ServiceDescriptor.Transient()); } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs index f5e3bf2123..652c936276 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkPageFilter_Exception_Rollback_Tests.cs @@ -14,7 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow; public class UnitOfWorkPageFilter_Exception_Rollback_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Replace(ServiceDescriptor.Transient()); } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs index 588c130a22..ab0fd586b3 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs @@ -118,14 +118,14 @@ public class ValidationTestController_Tests : AspNetCoreMvcTestBase public class DisableAutoModelValidationTestController_Tests : AspNetCoreMvcTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { options.AutoModelValidation = false; }); - base.ConfigureServices(context, services); + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiTestBase.cs index 99ca4da729..43167ce47d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiTestBase.cs @@ -1,8 +1,6 @@ -using Volo.Abp.AspNetCore.TestBase; +namespace Volo.Abp.AspNetCore.Mvc.UI; -namespace Volo.Abp.AspNetCore.Mvc.UI; - -public abstract class AbpAspNetCoreMvcUiTestBase : AbpAspNetCoreIntegratedTestBase +public abstract class AbpAspNetCoreMvcUiTestBase : AbpAspNetCoreTestBase { } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Program.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Program.cs new file mode 100644 index 0000000000..bd6027c624 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.Mvc.UI; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Startup.cs deleted file mode 100644 index 0e1954b630..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Startup.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.Mvc.UI; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Program.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Program.cs index 3f2eaedeb0..b7c7d4cd34 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Program.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Program.cs @@ -1,25 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; +using Volo.Abp.AspNetCore.TestBase; -namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests; +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); -public class Program +public partial class Program { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestBase.cs index b450dd97d2..1f7f5f2a82 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestBase.cs @@ -1,5 +1,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -public class AbpAspNetCoreMvcUiThemeSharedTestBase : AbpAspNetCoreTestBase +public class AbpAspNetCoreMvcUiThemeSharedTestBase : AbpAspNetCoreTestBase { } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestModule.cs index bfc1303970..a665d2c49d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/AbpAspNetCoreMvcUiThemeSharedTestModule.cs @@ -11,8 +11,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc. )] public class AbpAspNetCoreMvcUiThemeSharedTestModule : AbpModule { - public override void ConfigureServices(ServiceConfigurationContext context) - { - } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/PageToolbars/PageToolbar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/PageToolbars/PageToolbar_Tests.cs index 4bd8c2d036..cab4ca631c 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/PageToolbars/PageToolbar_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/PageToolbars/PageToolbar_Tests.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc. public class PageToolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Startup.cs deleted file mode 100644 index d17ee6203b..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Startup.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs index d9e5be8b2d..2c5394a931 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc. public class Toolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Configure(options => { @@ -35,7 +35,7 @@ public class Toolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase var claimsPrincipal = new ClaimsPrincipal(identity); var principalAccessor = Substitute.For(); principalAccessor.Principal.Returns(ci => claimsPrincipal); - Thread.CurrentPrincipal = claimsPrincipal; + services.Replace(ServiceDescriptor.Singleton(principalAccessor)); var themeManager = Substitute.For(); themeManager.CurrentTheme.Returns(x => null); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AspNetCoreMvcVersioningTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AspNetCoreMvcVersioningTestBase.cs index 0df183aca1..5792517562 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AspNetCoreMvcVersioningTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AspNetCoreMvcVersioningTestBase.cs @@ -1,5 +1,5 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning; -public abstract class AspNetCoreMvcVersioningTestBase : AbpAspNetCoreTestBase +public abstract class AspNetCoreMvcVersioningTestBase : AbpAspNetCoreTestBase { } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Program.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Program.cs new file mode 100644 index 0000000000..3d85fb71f9 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.Mvc.Versioning; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Startup.cs deleted file mode 100644 index 4ccb18feac..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Startup.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.Mvc.Versioning; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Program.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Program.cs new file mode 100644 index 0000000000..dbbce46a5e --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.App; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs deleted file mode 100644 index 8464f6e77b..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.App; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs index acfb7e54d0..acf053ced7 100644 --- a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs @@ -6,11 +6,11 @@ using Volo.Abp.AspNetCore.App; namespace Volo.Abp.AspNetCore.Serilog; -public class AbpSerilogTestBase : AbpAspNetCoreTestBase +public class AbpSerilogTestBase : AbpAspNetCoreTestBase { protected readonly CollectingSink CollectingSink = new CollectingSink(); - protected override IHostBuilder CreateHostBuilder() + protected override IHost CreateHost(IHostBuilder builder) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() @@ -19,8 +19,8 @@ public class AbpSerilogTestBase : AbpAspNetCoreTestBase .WriteTo.Sink(CollectingSink) .CreateLogger(); - return base.CreateHostBuilder() - .UseSerilog(); + builder.UseSerilog(); + return base.CreateHost(builder);; } protected LogEvent GetLogEvent(string text) diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs index b8f197d3c1..4782a5e768 100644 --- a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs @@ -33,18 +33,16 @@ public class Serilog_Enrichers_Tests : AbpSerilogTestBase _logger = ServiceProvider.GetRequiredService>(); } - protected override IHostBuilder CreateHostBuilder() + protected override void ConfigureServices(IServiceCollection services) { - return base.CreateHostBuilder().ConfigureServices(services => + services.Configure(options => { - services.Configure(options => + options.Tenants = new[] { - options.Tenants = new[] - { - new TenantConfiguration(_testTenantId, _testTenantName) - }; - }); + new TenantConfiguration(_testTenantId, _testTenantName) + }; }); + base.ConfigureServices(services); } [Fact] diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs index a79c4998e8..f78f27f141 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs @@ -9,13 +9,12 @@ using Volo.Abp.AspNetCore.TestBase; namespace Volo.Abp.AspNetCore; -public class AbpAspNetCoreTestBase : AbpAspNetCoreTestBase +public class AbpAspNetCoreTestBase : AbpAspNetCoreTestBase { - } -public abstract class AbpAspNetCoreTestBase : AbpAspNetCoreIntegratedTestBase - where TStartup : class +public abstract class AbpAspNetCoreTestBase : AbpWebApplicationFactoryIntegratedTest + where TProgram : class { protected virtual async Task GetResponseAsObjectAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs index 16799162bb..a87772536b 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs @@ -1,7 +1,5 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Shouldly; @@ -9,22 +7,8 @@ using Xunit; namespace Volo.Abp.AspNetCore; -public class AbpHostEnvironment_Tests : AbpAspNetCoreTestBase +public class AbpHostEnvironment_Tests : AbpAspNetCoreTestBase { - protected override IHostBuilder CreateHostBuilder() - { - var builder = base.CreateHostBuilder(); - builder.ConfigureHostConfiguration(x => x.Sources.Insert(0, - new MemoryConfigurationSource() - { - InitialData = new List> - { - new(HostDefaults.EnvironmentKey, Environments.Staging), - } - })); - return builder; - } - [Fact] public void Should_Set_Environment_From_IWebHostEnvironment() { diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Program.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Program.cs new file mode 100644 index 0000000000..841b2903c2 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Program.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Hosting; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(new WebApplicationOptions +{ + EnvironmentName = Environments.Staging +}); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Startup.cs deleted file mode 100644 index 133b77fcc8..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/Startup.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs index 3b1e3553bd..46f028596d 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AutoMapper.SampleClasses; @@ -24,6 +27,109 @@ public class AbpAutoMapperModule_Specific_ObjectMapper_Tests : AbpIntegratedTest dto.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. } + [Fact] + public void Specific_Object_Mapper_Should_Be_Used_For_Collections_If_Registered() + { + // IEnumerable + _objectMapper.Map, IEnumerable>(new List() + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var destination = new List() + { + new MyEntityDto2 { Number = 44 } + }; + var returnIEnumerable = _objectMapper.Map, IEnumerable>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnIEnumerable.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnIEnumerable).ShouldBeTrue(); + + // ICollection + _objectMapper.Map, ICollection>(new List() + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var returnICollection = _objectMapper.Map, ICollection>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnICollection.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnICollection).ShouldBeTrue(); + + // Collection + _objectMapper.Map, Collection>(new Collection() + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var destination2 = new Collection() + { + new MyEntityDto2 { Number = 44 } + }; + var returnCollection = _objectMapper.Map, Collection>( + new Collection() + { + new MyEntity { Number = 42 } + }, destination2); + returnCollection.First().Number.ShouldBe(43); + ReferenceEquals(destination2, returnCollection).ShouldBeTrue(); + + // IList + _objectMapper.Map, IList>(new List() + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var returnIList = _objectMapper.Map, IList>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnIList.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnIList).ShouldBeTrue(); + + // List + _objectMapper.Map, List>(new List() + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var returnList = _objectMapper.Map, List>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnList.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnList).ShouldBeTrue(); + + // Array + _objectMapper.Map(new MyEntity[] + { + new MyEntity { Number = 42 } + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var destinationArray = new MyEntityDto2[] + { + new MyEntityDto2 { Number = 40 } + }; + var returnArray = _objectMapper.Map(new MyEntity[] + { + new MyEntity { Number = 42 } + }, destinationArray); + + returnArray.First().Number.ShouldBe(43); + + // array should not be changed. Same as AutoMapper. + destinationArray.First().Number.ShouldBe(40); + ReferenceEquals(returnArray, destinationArray).ShouldBeFalse(); + } + [Fact] public void Should_Use_Destination_Object_Constructor_If_Available() { diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs index e6e17b253c..ca98017e0a 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs @@ -31,15 +31,15 @@ public class RepositoryRegistration_Tests //Assert //MyTestAggregateRootWithoutPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); //MyTestAggregateRootWithGuidPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); @@ -69,24 +69,24 @@ public class RepositoryRegistration_Tests //Assert //MyTestAggregateRootWithoutPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); //MyTestAggregateRootWithGuidPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); //MyTestEntityWithInt32Pk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyBasicRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); } @@ -114,20 +114,20 @@ public class RepositoryRegistration_Tests services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); //MyTestAggregateRootWithGuidPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); - services.ShouldContainTransient(typeof(IReadOnlyBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); //MyTestEntityWithInt32Pk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyBasicRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); } @@ -209,10 +209,10 @@ public class RepositoryRegistration_Tests services.ShouldNotContainService(typeof(IRepository)); //MyTestAggregateRootWithGuidPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestDefaultRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestDefaultRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestDefaultRepository)); } @@ -234,11 +234,11 @@ public class RepositoryRegistration_Tests new MyTestRepositoryRegistrar(options).AddRepositories(); //MyTestAggregateRootWithGuidPk - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); - services.ShouldContainTransient(typeof(IReadOnlyRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); - services.ShouldContainTransient(typeof(IReadOnlyBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository)); + services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository)); services.ShouldContainTransient(typeof(IBasicRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); services.ShouldContainTransient(typeof(IRepository), typeof(MyTestAggregateRootWithDefaultPkCustomRepository)); } @@ -407,7 +407,7 @@ public class RepositoryRegistration_Tests public class MyTestAggregateRootWithDefaultPkEmptyRepository : IMyTestAggregateRootWithDefaultPkEmptyRepository { - + public bool? IsChangeTrackingEnabled { get; set; } } public class TestDbContextRegistrationOptions : AbpCommonDbContextRegistrationOptions diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs new file mode 100644 index 0000000000..87b487b68a --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ChangeTracking/ChangeTrackingInterceptor_Tests.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.ChangeTracking; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.TestApp.Domain; +using Volo.Abp.TestApp.Testing; +using Xunit; + +namespace Volo.Abp.EntityFrameworkCore.ChangeTracking; + +public class ChangeTrackingInterceptor_Tests : TestAppTestBase +{ + [Fact] + public async Task ReadOnly_Repository_Should_Not_Track_Entities() + { + await AddSomePeopleAsync(); + + var readOnlyRepository = GetRequiredService>(); + + await WithUnitOfWorkAsync(async () => + { + var db = await readOnlyRepository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + + var service = GetRequiredService(); + var list = await service.GetPeoplesAsync(); + list.Count.ShouldBeGreaterThan(0); + + // RepositoryInterceptor always not track entities + db.ChangeTracker.Entries().Count().ShouldBe(0); + }); + } + + [Fact] + public async Task RepositoryInterceptor_Test() + { + await AddSomePeopleAsync(); + + var repository = GetRequiredService>(); + + await WithUnitOfWorkAsync(async () => + { + var service = GetRequiredService(); + var db = await repository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + + var list = await service.GetPeoplesAsync(); + list.Count.ShouldBeGreaterThan(0); + + db.ChangeTracker.Entries().Count().ShouldBe(1); // Track one entity from GetPeopleAsync + }); + + await WithUnitOfWorkAsync(async () => + { + var service = GetRequiredService(); + var db = await repository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + + var list = await service.GetPeoplesAsync(); + list.Count.ShouldBeGreaterThan(0); + + db.ChangeTracker.Entries().Count().ShouldBe(1); // Track one entity from GetPeoplesAsync + }); + + await WithUnitOfWorkAsync(async () => + { + var service = GetRequiredService(); + var db = await repository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + + var entityChangeTrackingProvider = GetRequiredService(); + // Disable entity change tracking + using (entityChangeTrackingProvider.Change(false)) + { + var list = await service.GetPeoplesAsync(); + list.Count.ShouldBeGreaterThan(0); + db.ChangeTracker.Entries().Count().ShouldBe(0); + } + }); + } + + private async Task AddSomePeopleAsync() + { + var repository = GetRequiredService>(); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people1", 18)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people2", 19)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people3", 20)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people4", 21)); + } +} + +public class MyService : ITransientDependency +{ + private readonly IRepository _repository; + + public MyService(IRepository repository) + { + _repository = repository; + } + + [DisableEntityChangeTracking] + public virtual async Task> GetPeoplesAsync() + { + await GetPeopleAsync(); + return await _repository.GetListAsync(); + } + + [EnableEntityChangeTracking] + public virtual async Task GetPeopleAsync() + { + var p1 = await _repository.FindAsync(x => x.Name == "people1"); + return p1; + } +} + +public class MyReadOnlyService : MyService +{ + public MyReadOnlyService(IReadOnlyRepository repository) + : base(repository.As>()) + { + } +} + + +[EnableEntityChangeTracking] +public class MyServiceEnableEntityChangeTracking : ITransientDependency +{ + private readonly IRepository _repository; + + public MyServiceEnableEntityChangeTracking(IRepository repository) + { + _repository = repository; + } + + public virtual async Task> GetPeoplesAsync() + { + var p1 = await GetPeopleAsync(); + var p2 = await _repository.FindAsync(x => x.Name == "people2"); + + return new List {p1, p2}; + } + + [DisableEntityChangeTracking] + public virtual async Task GetPeopleAsync() + { + var p1 = await _repository.FindAsync(x => x.Name == "people1"); + return p1; + } +} + +public class MyServiceChangeTrackingByEntityChangeTrackingProvider : ITransientDependency +{ + private readonly IRepository _repository; + + public MyServiceChangeTrackingByEntityChangeTrackingProvider(IRepository repository) + { + _repository = repository; + } + + public virtual async Task> GetPeoplesAsync() + { + return await _repository.GetListAsync(); + } +} diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/ReadOnlyRepository_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/ReadOnlyRepository_Tests.cs new file mode 100644 index 0000000000..6213a6e114 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/ReadOnlyRepository_Tests.cs @@ -0,0 +1,127 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Shouldly; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.TestApp.Domain; +using Volo.Abp.TestApp.Testing; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.EntityFrameworkCore.Repositories; + +public class ReadOnlyRepository_Tests : TestAppTestBase +{ + [Fact] + public async Task ReadOnlyRepository_Should_NoTracking() + { + // Non-read-only repository tracking default + await WithUnitOfWorkAsync(async () => + { + var repository = GetRequiredService>(); + var db = await repository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + var list = await repository.GetListAsync(); + list.Count.ShouldBeGreaterThan(0); + db.ChangeTracker.Entries().Count().ShouldBe(list.Count); + }); + + // Read-only repository no tracking default + await WithUnitOfWorkAsync(async () => + { + var readonlyRepository = GetRequiredService>(); + var db = await readonlyRepository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + var list = await readonlyRepository.GetListAsync(); + list.Count.ShouldBeGreaterThan(0); + db.ChangeTracker.Entries().Count().ShouldBe(0); + }); + + // Read-only repository can tracking manually by AsTracking + await WithUnitOfWorkAsync(async () => + { + var readonlyRepository = GetRequiredService>(); + var db = await readonlyRepository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + var list = await (await readonlyRepository.ToEfCoreRepository().GetQueryableAsync()).AsTracking().ToListAsync(); + list.Count.ShouldBeGreaterThan(0); + db.ChangeTracker.Entries().Count().ShouldBe(list.Count); + }); + } + + [Fact] + public async Task Repository_Should_Support_Tracking_Or_NoTracking() + { + var repository = GetRequiredService>(); + + await WithUnitOfWorkAsync(async () => + { + await repository.InsertAsync(new Person(Guid.NewGuid(), "people1", 18)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people2", 19)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people3", 20)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people4", 21)); + }); + + await WithUnitOfWorkAsync(async () => + { + var db = await repository.GetDbContextAsync(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + using (repository.DisableTracking()) + { + var p1 = await repository.FindAsync(x => x.Name == "people1"); + p1.ShouldNotBeNull(); + db.ChangeTracker.Entries().Count().ShouldBe(0); + } + + var p2 = await repository.FindAsync(x => x.Name == "people2"); + p2.ShouldNotBeNull(); + db.ChangeTracker.Entries().Count().ShouldBe(1); + + repository.DisableTracking(); + var p3 = await repository.FindAsync(x => x.Name == "people3"); + p3.ShouldNotBeNull(); + db.ChangeTracker.Entries().Count().ShouldBe(1); + + repository.EnableTracking(); + var p4 = await repository.FindAsync(x => x.Name == "people4"); + p4.ShouldNotBeNull(); + db.ChangeTracker.Entries().Count().ShouldBe(2); + }); + } + + [Fact] + public async Task ReadOnlyRepository_Should_NoTracking_In_UOW() + { + var repository = GetRequiredService>(); + var readonlyRepository = GetRequiredService>(); + + await WithUnitOfWorkAsync(async () => + { + await repository.InsertAsync(new Person(Guid.NewGuid(), "people1", 18)); + await repository.InsertAsync(new Person(Guid.NewGuid(), "people2", 19)); + }); + + using (var uow = GetRequiredService().Begin()) + { + var p1 = await repository.FirstOrDefaultAsync(x => x.Name == "people1"); + p1.ShouldNotBeNull(); + p1.ChangeName("people1-updated"); + + var p2 = await readonlyRepository.FirstOrDefaultAsync(x => x.Name == "people2"); + p2.ShouldNotBeNull(); + p2.ChangeName("people2-updated"); + + await uow.CompleteAsync(); + } + + await WithUnitOfWorkAsync(async () => + { + (await repository.FirstOrDefaultAsync(x => x.Name == "people1")).ShouldBeNull(); + (await repository.FirstOrDefaultAsync(x => x.Name == "people1-updated")).ShouldNotBeNull(); + + (await readonlyRepository.FirstOrDefaultAsync(x => x.Name == "people2")).ShouldNotBeNull(); + (await readonlyRepository.FirstOrDefaultAsync(x => x.Name == "people2-updated")).ShouldBeNull(); + }); + } +} diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestBase.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestBase.cs index 9ae4370b38..dfa5c335b2 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestBase.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestBase.cs @@ -2,7 +2,7 @@ using Volo.Abp.AspNetCore; namespace Volo.Abp.Http; -public abstract class AbpHttpClientTestBase : AbpAspNetCoreTestBase +public abstract class AbpHttpClientTestBase : AbpAspNetCoreTestBase { } diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs index 6540b717d3..5e9107a23b 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpClientTestModule.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.DynamicProxying; diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs index 8469ba121a..f679ccd9c9 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_AbpRemoteCallException_Tests.cs @@ -20,7 +20,7 @@ public class RegularTestControllerClientProxy_AbpRemoteCallException_Tests : Abp _controller = ServiceProvider.GetRequiredService(); } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + protected override void ConfigureServices(IServiceCollection services) { services.Replace(ServiceDescriptor.Singleton()); } diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Program.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Program.cs new file mode 100644 index 0000000000..a0cfe08f84 --- /dev/null +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Http; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +} diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Startup.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Startup.cs deleted file mode 100644 index 063b9999c1..0000000000 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Startup.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace Volo.Abp.Http; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app) - { - app.InitializeApplication(); - } -} diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json index cdabc68af1..4691a2268e 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "لقد تلقينا طلب استرداد الحساب! إذا بدأت هذا الطلب ، فانقر فوق الارتباط التالي لإعادة تعيين كلمة المرور الخاصة بك.", "ResetMyPassword": "إعادة تعيين كلمة المرور الخاصة بي", "AccessDenied": "تم الرفض!", - "AccessDeniedMessage": "ليس لديك حق الوصول إلى هذا المورد." + "AccessDeniedMessage": "ليس لديك حق الوصول إلى هذا المورد.", + "OrRegisterWith": "أو التسجيل بـ:", + "RegisterUsingYourProviderAccount": "قم بالتسجيل باستخدام حسابك في {0}" } } \ No newline at end of file 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 faec2b2a22..aeae890d54 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 @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Obdrželi jsme žádost o obnovení účtu! Pokud jste tento požadavek iniciovali, klikněte na následující odkaz a obnovte své heslo.", "ResetMyPassword": "Obnovit moje heslo", "AccessDenied": "Přístup odepřen!", - "AccessDeniedMessage": "K tomuto zdroji nemáte přístup." + "AccessDeniedMessage": "K tomuto zdroji nemáte přístup.", + "OrRegisterWith": "Nebo se registrujte pomocí:", + "RegisterUsingYourProviderAccount": "Registrovat pomocí vašeho účtu {0}" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/da.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/da.json index 895638aede..24283d06c8 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/da.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/da.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Vi har modtaget en forespørgsel for gendannelse af konto! Hvis du har lavet denne forespørgsel, klik på det efterfølgende link for at nulstille dit kodeord.", "ResetMyPassword": "Nulstil mit kodeord", "AccessDenied": "Adgang nægtet!", - "AccessDeniedMessage": "Du har ikke adgang til denne ressource." + "AccessDeniedMessage": "Du har ikke adgang til denne ressource.", + "OrRegisterWith": "Eller registrér med:", + "RegisterUsingYourProviderAccount": "Registrér med din {0} konto" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de.json index fb1f4b7153..64c86e4abe 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Wir haben eine Anfrage zur Wiederherstellung des Kontos erhalten! Wenn Sie diese Anforderung initiiert haben, klicken Sie auf den folgenden Link, um Ihr Passwort zurückzusetzen.", "ResetMyPassword": "Mein Passwort zurücksetzen", "AccessDenied": "Zugriff abgelehnt!", - "AccessDeniedMessage": "Sie haben keinen Zugriff auf diese Ressource." + "AccessDeniedMessage": "Sie haben keinen Zugriff auf diese Ressource.", + "OrRegisterWith": "Oder registrieren Sie sich mit:", + "RegisterUsingYourProviderAccount": "Registrieren Sie sich mit Ihrem {0} Benutzerkonto" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/el.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/el.json index 6a6788300d..a64dca5ef5 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/el.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/el.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Λάβαμε ένα αίτημα ανάκτησης λογαριασμού! Εάν υποβάλατε αυτό το αίτημα, κάντε κλικ στον παρακάτω σύνδεσμο για να επαναφέρετε τον κωδικό πρόσβασής σας.", "ResetMyPassword": "Επαναφορά του κωδικού πρόσβασής μου", "AccessDenied": "Δεν επιτρέπεται η πρόσβαση!", - "AccessDeniedMessage": "Δεν έχετε πρόσβαση σε αυτόν τον πόρο." + "AccessDeniedMessage": "Δεν έχετε πρόσβαση σε αυτόν τον πόρο.", + "OrRegisterWith": "Ή εγγραφείτε με:", + "RegisterUsingYourProviderAccount": "Εγγραφείτε χρησιμοποιώντας τον λογαριασμό σας {0}" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en-GB.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en-GB.json index 4f1486a78e..f4208335b5 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en-GB.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en-GB.json @@ -61,6 +61,8 @@ "Volo.Account:InvalidEmailAddress": "Cannot find the given email address: {0}", "PasswordReset": "Password reset", "PasswordResetInfoInEmail": "We received an account recovery request! If you initiated this request, click the following link to reset your password.", - "ResetMyPassword": "Reset my password" + "ResetMyPassword": "Reset my password", + "OrRegisterWith": "Or register with", + "RegisterUsingYourProviderAccount": "Register using your {0} account" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json index 706f92bbd5..183bb5363e 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json @@ -66,6 +66,8 @@ "PasswordResetInfoInEmail": "We received an account recovery request! If you initiated this request, click the following link to reset your password.", "ResetMyPassword": "Reset my password", "AccessDenied": "Access denied!", - "AccessDeniedMessage": "You do not have access to this resource." + "AccessDeniedMessage": "You do not have access to this resource.", + "OrRegisterWith": "Or register with", + "RegisterUsingYourProviderAccount": "Register using your {0} account" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es-mx.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es-mx.json index b3bcad86f9..6793e58986 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es-mx.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es-mx.json @@ -34,6 +34,8 @@ "NewPasswordConfirmFailed": "Por favor, confirme la nueva contraseña.", "NewPasswordSameAsOld": "La nueva contraseña debe ser diferente de la contraseña actual.", "Manage": "Administrar", - "MyAccount": "Mi cuenta" + "MyAccount": "Mi cuenta", + "OrRegisterWith": "O registrarse con", + "RegisterUsingYourProviderAccount": "Registrarse con su cuenta de {0} " } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json index 0e883a1372..9fd52c8450 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Recibimos una solicitud de recuperación de cuenta. Si inició esta solicitud, haga clic en el siguiente enlace para restablecer su contraseña.", "ResetMyPassword": "Restablecer mi contraseña", "AccessDenied": "¡Acceso denegado!", - "AccessDeniedMessage": "No tienes acceso a este recurso." + "AccessDeniedMessage": "No tienes acceso a este recurso.", + "OrRegisterWith": "O registrarse con:", + "RegisterUsingYourProviderAccount": "Registrarse con su cuenta de {0} " } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fa.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fa.json index e7c5ee084e..4fc0685b79 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fa.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fa.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "ما درخواست بازیابی حساب دریافت کردیم! اگر این درخواست را آغاز کرده اید, برای بازنشانی گذرواژه خود روی پیوند زیر کلیک کنید.", "ResetMyPassword": "بازنشانی گذرواژه من", "AccessDenied": "دسترسی ممنوع!", - "AccessDeniedMessage": "شما به این منبع دسترسی ندارید." + "AccessDeniedMessage": "شما به این منبع دسترسی ندارید.", + "OrRegisterWith": "یا ثبت نام کنید با:", + "RegisterUsingYourProviderAccount": "با استفاده از حساب {0} خود ثبت نام کنید" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json index 027928ead3..2f0ae2c574 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json @@ -66,6 +66,8 @@ "PasswordResetInfoInEmail": "Saimme tilin palautuspyynnön! Jos aloitit tämän pyynnön, voit nollata salasanasi napsauttamalla seuraavaa linkkiä.", "ResetMyPassword": "Vaihda salasanani", "AccessDenied": "Pääsy evätty!", - "AccessDeniedMessage": "Sinulla ei ole pääsyä tähän resurssiin." + "AccessDeniedMessage": "Sinulla ei ole pääsyä tähän resurssiin.", + "OrRegisterWith": "Tai rekisteröidy:", + "RegisterUsingYourProviderAccount": "Rekisteröidy {0} -tililläsi" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json index b1e547652d..aa640abf1a 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Nous avons reçu une demande de récupération de compte! Si vous avez lancé cette demande, cliquez sur le lien suivant pour réinitialiser votre mot de passe.", "ResetMyPassword": "Réinitialiser mon mot de passe", "AccessDenied": "Accès refusé!", - "AccessDeniedMessage": "Vous n'avez pas accès à cette ressource." + "AccessDeniedMessage": "Vous n'avez pas accès à cette ressource.", + "OrRegisterWith": "Or register with", + "RegisterUsingYourProviderAccount": "Register using your {0} account" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json index fd93420216..a424deae00 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "हमें एक खाता पुनर्प्राप्ति अनुरोध प्राप्त हुआ! यदि आपने यह अनुरोध किया है, तो अपना पासवर्ड रीसेट करने के लिए निम्न लिंक पर क्लिक करें।", "ResetMyPassword": "अपना पासवर्ड रीसेट करें", "AccessDenied": "पहुंच अस्वीकृत!", - "AccessDeniedMessage": "आपके पास इस संसाधन तक पहुँच नहीं है।" + "AccessDeniedMessage": "आपके पास इस संसाधन तक पहुँच नहीं है।", + "OrRegisterWith": "या इसके साथ पंजीकरण करें:", + "RegisterUsingYourProviderAccount": "अपने {0} खाते का उपयोग करके पंजीकरण करें" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hr.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hr.json index 665755a2dd..8ec48e7a09 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hr.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hr.json @@ -66,6 +66,8 @@ "PasswordResetInfoInEmail": "Primili smo zahtjev za oporavak računa! Ako ste vi pokrenuli ovaj zahtjev, kliknite na sljedeću poveznicu za ponovno postavljanje lozinke.", "ResetMyPassword": "Resetirati moju lozinku", "AccessDenied": "Pristup odbijen!", - "AccessDeniedMessage": "Nemate pristup ovom resursu." + "AccessDeniedMessage": "Nemate pristup ovom resursu.", + "OrRegisterWith": "Ili se registrirajte sa:", + "RegisterUsingYourProviderAccount": "Registrirajte se koristeći svoj {0} račun" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hu.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hu.json index 3c97fd290d..481fa2733a 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hu.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hu.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Fiók-helyreállítási kérelmet kaptunk! Ha Ön kezdeményezte ezt a kérést, kattintson a következő hivatkozásra jelszava visszaállításához.", "ResetMyPassword": "Jelszavam visszaállítása", "AccessDenied": "Hozzáférés megtagadva!", - "AccessDeniedMessage": "Nincs hozzáférése ehhez az erőforráshoz." + "AccessDeniedMessage": "Nincs hozzáférése ehhez az erőforráshoz.", + "OrRegisterWith": "Vagy regisztráljon:", + "RegisterUsingYourProviderAccount": "Regisztráljon a(z) {0} fiókjával" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/is.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/is.json index e309962242..f33db6eadb 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/is.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/is.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Við fengum beiðni um endurheimt reiknings! Ef þú stofnaðir þessa beiðni skaltu smella á eftirfarandi krækju til að endurstilla lykilorðið þitt.", "ResetMyPassword": "Endurstilla lykilorðið mitt", "AccessDenied": "Aðgangi hafnað!", - "AccessDeniedMessage": "Þú hefur ekki aðgang að þessari auðlind." + "AccessDeniedMessage": "Þú hefur ekki aðgang að þessari auðlind.", + "OrRegisterWith": "Eða skráðu þig með:", + "RegisterUsingYourProviderAccount": "Skráðu þig með {0} aðganginum þínum" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json index 6e4521c8f7..0b5f3dbcf2 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Abbiamo ricevuto una richiesta di recupero dell'account! Se hai fatto tu questa richiesta fai clic sul seguente collegamento per reimpostare la password.", "ResetMyPassword": "Reimposta la mia password", "AccessDenied": "Accesso negato!", - "AccessDeniedMessage": "Non hai accesso a questa risorsa." + "AccessDeniedMessage": "Non hai accesso a questa risorsa.", + "OrRegisterWith": "Oppure registrati con:", + "RegisterUsingYourProviderAccount": "Registrati utilizzando il tuo account {0}" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/nl.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/nl.json index b804e517a9..d5d400277f 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/nl.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/nl.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "We hebben een verzoek ontvangen om uw wachtwoord opnieuw in te stellen. Als u dit verzoek heeft ingediend, klikt u op de volgende link om een nieuw wachtwoord in te stellen.", "ResetMyPassword": "Reset mijn wachtwoord", "AccessDenied": "Toegang geweigerd!", - "AccessDeniedMessage": "U heeft geen toegang tot deze bron." + "AccessDeniedMessage": "U heeft geen toegang tot deze bron.", + "OrRegisterWith": "Of registreer met:", + "RegisterUsingYourProviderAccount": "Registreer met uw {0} -account" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pl-PL.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pl-PL.json index c3596c8aa5..0fdab745de 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pl-PL.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pl-PL.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Otrzymaliśmy prośbę o odzyskanie konta! Jeśli zainicjowałeś to żądanie, kliknij poniższy link, aby zresetować hasło.", "ResetMyPassword": "Zresetować moje hasło", "AccessDenied": "Brak dostępu!", - "AccessDeniedMessage": "Nie masz dostępu do tego zasobu." + "AccessDeniedMessage": "Nie masz dostępu do tego zasobu.", + "OrRegisterWith": "Lub zarejestruj się za pomocą:", + "RegisterUsingYourProviderAccount": "Zarejestruj się za pomocą konta {0}" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json index 732d804bbe..5b54bc91c5 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Recebemos um pedido de recuperação de conta! Se você iniciou esta solicitação, clique no link a seguir para redefinir sua senha.", "ResetMyPassword": "Resetar minha senha", "AccessDenied": "Acesso negado!", - "AccessDeniedMessage": "Você não tem acesso a este recurso." + "AccessDeniedMessage": "Você não tem acesso a este recurso.", + "OrRegisterWith": "Ou registre-se com:", + "RegisterUsingYourProviderAccount": "Registre-se utilizando sua conta {0}" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json index c2a75c3401..732a4103ec 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Am primit o cerere de recuperare a contului! Dacă dumneavoastră aţi iniţiat această cerere, daţi click pe următorul link pentru a vă reseta parola.", "ResetMyPassword": "Resetează-mi parola", "AccessDenied": "Acces interzis!", - "AccessDeniedMessage": "Nu aveţi acces la această resursă." + "AccessDeniedMessage": "Nu aveţi acces la această resursă.", + "OrRegisterWith": "Sau înregistraţi-vă cu:", + "RegisterUsingYourProviderAccount": "Înregistraţi-vă folosindu-vă contul {0}" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ru.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ru.json index 88250e8d03..8413c32831 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ru.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ru.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Мы получили запрос на восстановление аккаунта! Если вы инициировали этот запрос, щелкните следующую ссылку, чтобы сбросить пароль.", "ResetMyPassword": "Сбросить пароль", "AccessDenied": "В доступе отказано!", - "AccessDeniedMessage": "У вас нет доступа к этому ресурсу." + "AccessDeniedMessage": "У вас нет доступа к этому ресурсу.", + "OrRegisterWith": "Или зарегистрируйтесь с помощью:", + "RegisterUsingYourProviderAccount": "Зарегистрируйтесь, используя свой {0} аккаунт" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json index 6ca224455a..d69c0da03e 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Dostali sme žiadosť na obnovenie účtu! Ak ste o zmenu žiadali vy, kliknite na nasledujúci link a obnovte svoje heslo.", "ResetMyPassword": "Obnovte moje heslo", "AccessDenied": "Prístup zamietnutý!", - "AccessDeniedMessage": "K tomuto zdroju nemáte prístup." + "AccessDeniedMessage": "K tomuto zdroju nemáte prístup.", + "OrRegisterWith": "Alebo sa zaregistrujte pomocou:", + "RegisterUsingYourProviderAccount": "Zaregistrujte sa pomocou svojho {0} účtu" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json index 322e04cf76..4442227ad6 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "Prejeta je bila zahteva za obnovitev računa! V kolikor ste vi sprožili zahtevo, kliknite na sledečo povezavo, da ponastavite geslo.", "ResetMyPassword": "Ponastavi geslo", "AccessDenied": "Dostop zavrnjen!", - "AccessDeniedMessage": "Nimate dostopa do tega vira." + "AccessDeniedMessage": "Nimate dostopa do tega vira.", + "OrRegisterWith": "Ali pa se registrirajte z:", + "RegisterUsingYourProviderAccount": "Registrirajte se z uporabo vašega {0} računa" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json index c63eb86cef..0e53963f9a 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json @@ -66,6 +66,8 @@ "PasswordResetInfoInEmail": "Şifrenizi sıfırlamanız için bir talep aldık! Eğer bu talebi siz gerçekleştirmişseniz, şifrenizi sıfırlamak için bağlantıya tıklayın.", "ResetMyPassword": "Şifremi sıfırla", "AccessDenied": "Erişim reddedildi!", - "AccessDeniedMessage": "Bu kaynağa erişiminiz yok." + "AccessDeniedMessage": "Bu kaynağa erişiminiz yok.", + "OrRegisterWith": "Veya bunlarla kayıt ol:", + "RegisterUsingYourProviderAccount": "{0} hesabınızla kayıt olun." } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/vi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/vi.json index e10ae3ebe1..eae396b011 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/vi.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/vi.json @@ -63,6 +63,8 @@ "PasswordResetInfoInEmail": "Chúng tôi đã nhận được yêu cầu khôi phục tài khoản! Nếu bạn bắt đầu yêu cầu này, hãy nhấp vào liên kết sau để đặt lại mật khẩu của bạn.", "ResetMyPassword": "Đặt lại mật khẩu của tôi", "AccessDenied": "Quyền truy cập bị từ chối!", - "AccessDeniedMessage": "Bạn không có quyền truy cập vào tài nguyên này." + "AccessDeniedMessage": "Bạn không có quyền truy cập vào tài nguyên này.", + "OrRegisterWith": "Hoặc đăng ký bằng:", + "RegisterUsingYourProviderAccount": "Đăng ký bằng tài khoản {0} của bạn" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json index 1cfabd4d62..635971e7db 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json @@ -66,6 +66,8 @@ "PasswordResetInfoInEmail": "我们收到了帐户恢复请求!如果你发起了此请求,请单击以下链接以重置密码.", "ResetMyPassword": "重置我的密码", "AccessDenied": "拒绝访问!", - "AccessDeniedMessage": "你无权访问此资源." + "AccessDeniedMessage": "你无权访问此资源.", + "OrRegisterWith": "或注册:", + "RegisterUsingYourProviderAccount": "使用你的{0}帐户注册" } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json index 8749163c1d..a782aa42dc 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json @@ -64,6 +64,8 @@ "PasswordResetInfoInEmail": "我們收到了帳戶恢復請求!如果你發起了此請求,請點擊以下連結以重置密碼.", "ResetMyPassword": "重置我的密碼", "AccessDenied": "拒絕訪問!", - "AccessDeniedMessage": "您無權訪問此資源." + "AccessDeniedMessage": "您無權訪問此資源.", + "OrRegisterWith": "或是註冊用:", + "RegisterUsingYourProviderAccount": "使用你的{0}帳號註冊" } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml index 59d5ee852f..137715804a 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml @@ -12,20 +12,42 @@ @L["Login"]
- @if (!Model.IsExternalLogin) + @if (!Model.IsExternalLogin && Model.EnableLocalRegister) { } + + @if(Model.EnableLocalRegister || Model.IsExternalLogin) + { + + } - - - @if (!Model.IsExternalLogin) + @if (!Model.IsExternalLogin && Model.EnableLocalRegister) { } -
- @L["Register"] -
+ + @if(Model.EnableLocalRegister || Model.IsExternalLogin) + { +
+ @L["Register"] +
+ } + + + @if (!Model.IsExternalLogin && Model.VisibleExternalProviders.Any()) + { +
+
@L["OrRegisterWith"]
+
+ @foreach (var provider in Model.VisibleExternalProviders) + { + + } +
+
+ } + 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 f9489f7797..7bc536ba9d 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 @@ -1,7 +1,10 @@ +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -32,16 +35,43 @@ public class RegisterModel : AccountPageModel [BindProperty(SupportsGet = true)] public string ExternalLoginAuthSchema { get; set; } - - public RegisterModel(IAccountAppService accountAppService) + + public IEnumerable ExternalProviders { get; set; } + public IEnumerable VisibleExternalProviders => ExternalProviders.Where(x => !string.IsNullOrWhiteSpace(x.DisplayName)); + public bool EnableLocalRegister { get; set; } + public bool IsExternalLoginOnly => EnableLocalRegister == false && ExternalProviders?.Count() == 1; + public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null; + + protected IAuthenticationSchemeProvider SchemeProvider { get; } + + protected AbpAccountOptions AccountOptions { get; } + + public RegisterModel( + IAccountAppService accountAppService, + IAuthenticationSchemeProvider schemeProvider, + IOptions accountOptions) { + SchemeProvider = schemeProvider; AccountAppService = accountAppService; + AccountOptions = accountOptions.Value; } public virtual async Task OnGetAsync() { - await CheckSelfRegistrationAsync(); + ExternalProviders = await GetExternalProviders(); + + if (!await CheckSelfRegistrationAsync()) + { + if (IsExternalLoginOnly) + { + return await OnPostExternalLogin(ExternalLoginScheme); + } + + Alerts.Warning(L["SelfRegistrationDisabledMessage"]); + } + await TrySetEmailAsync(); + return Page(); } @@ -76,7 +106,12 @@ public class RegisterModel : AccountPageModel { try { - await CheckSelfRegistrationAsync(); + ExternalProviders = await GetExternalProviders(); + + if (!await CheckSelfRegistrationAsync()) + { + throw new UserFriendlyException(L["SelfRegistrationDisabledMessage"]); + } if (IsExternalLogin) { @@ -147,13 +182,46 @@ public class RegisterModel : AccountPageModel await SignInManager.SignInAsync(user, isPersistent: true, ExternalLoginAuthSchema); } - protected virtual async Task CheckSelfRegistrationAsync() + protected virtual async Task CheckSelfRegistrationAsync() { - if (!await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled) || - !await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin)) + EnableLocalRegister = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin) && + await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled); + + if (IsExternalLogin) { - throw new UserFriendlyException(L["SelfRegistrationDisabledMessage"]); + return true; } + + if (!EnableLocalRegister) + { + return false; + } + + return true; + } + + protected virtual async Task> GetExternalProviders() + { + + var schemes = await SchemeProvider.GetAllSchemesAsync(); + + return schemes + .Where(x => x.DisplayName != null || x.Name.Equals(AccountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase)) + .Select(x => new ExternalProviderModel + { + DisplayName = x.DisplayName, + AuthenticationScheme = x.Name + }) + .ToList(); + } + + protected virtual async Task OnPostExternalLogin(string provider) + { + var redirectUrl = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }); + var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + properties.Items["scheme"] = provider; + + return await Task.FromResult(Challenge(properties, provider)); } public class PostInput @@ -173,4 +241,10 @@ public class RegisterModel : AccountPageModel [DisableAuditing] public string Password { get; set; } } + + public class ExternalProviderModel + { + public string DisplayName { get; set; } + public string AuthenticationScheme { get; set; } + } } diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml index e24b1dd5af..9ac8ee9462 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml @@ -1,11 +1,8 @@ @page -@using System.Globalization @using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab -@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Utils @using Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers @using Volo.Abp.Users -@using Volo.Blogging @using Volo.Blogging.Areas.Blog.Helpers.TagHelpers @using Volo.Blogging.Localization @model Volo.Blogging.Pages.Members.IndexModel diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css index 668e566cba..3a2c2675c5 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css @@ -1,6 +1,3 @@ .post-desc { overflow-wrap: break-word; } -a:not(#all-posts-tab,#edit-profile-tab) { - color: unset!important; -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs index a85783ee3f..ca273cd94a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs @@ -15,4 +15,8 @@ public class UpdateCommentInput : ExtensibleObject, IHasConcurrencyStamp public string Text { get; set; } public string ConcurrencyStamp { get; set; } + + public Guid? CaptchaToken { get; set; } + + public int CaptchaAnswer { get; set; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs index 00851bce15..79163c5b03 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs @@ -1,7 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; +using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.ObjectMapping; using Volo.CmsKit.Comments; @@ -12,7 +14,7 @@ using Volo.CmsKit.Public.Web.Security.Captcha; namespace Volo.CmsKit.Public.Web.Controllers; //[Route("cms-kit/public-comments")] -public class CmsKitPublicCommentsController : AbpController +public class CmsKitPublicCommentsController : CmsKitPublicControllerBase { public ICommentPublicAppService CommentPublicAppService { get; } protected CmsKitCommentOptions CmsKitCommentOptions { get; } @@ -31,12 +33,35 @@ public class CmsKitPublicCommentsController : AbpController [HttpPost] public virtual async Task ValidateAsync([FromBody] CreateCommentWithParametersInput input) { - if (CmsKitCommentOptions.IsRecaptchaEnabled && input.CaptchaToken.HasValue) + if (CmsKitCommentOptions.IsRecaptchaEnabled) { - SimpleMathsCaptchaGenerator.Validate(input.CaptchaToken.Value, input.CaptchaAnswer); + CheckCaptchaTokenNullity(input.CaptchaToken); + + await SimpleMathsCaptchaGenerator.ValidateAsync(input.CaptchaToken.Value, input.CaptchaAnswer); } var dto = ObjectMapper.Map (input); await CommentPublicAppService.CreateAsync(input.EntityType, input.EntityId, dto); } + + [HttpPost] + public virtual async Task UpdateAsync(Guid id, [FromBody] UpdateCommentInput input) + { + if (CmsKitCommentOptions.IsRecaptchaEnabled) + { + CheckCaptchaTokenNullity(input.CaptchaToken); + + await SimpleMathsCaptchaGenerator.ValidateAsync(input.CaptchaToken.Value, input.CaptchaAnswer); + } + + await CommentPublicAppService.UpdateAsync(id, input); + } + + private void CheckCaptchaTokenNullity(Guid? captchaToken) + { + if (!captchaToken.HasValue) + { + throw new UserFriendlyException(L["CaptchaCodeMissingMessage"]); + } + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicControllerBase.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicControllerBase.cs new file mode 100644 index 0000000000..f22444036d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicControllerBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Localization; + +namespace Volo.CmsKit.Public.Web.Controllers; + +public abstract class CmsKitPublicControllerBase : AbpController +{ + public CmsKitPublicControllerBase() + { + LocalizationResource = typeof(CmsKitResource); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicGlobalResourcesController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicGlobalResourcesController.cs index 115dfd3fcc..eb4356e8b9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicGlobalResourcesController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicGlobalResourcesController.cs @@ -11,7 +11,7 @@ using Volo.CmsKit.Public.GlobalResources; namespace Volo.CmsKit.Public.Web.Controllers; [Route("cms-kit/global-resources")] -public class CmsKitPublicGlobalResourcesController: AbpController +public class CmsKitPublicGlobalResourcesController : CmsKitPublicControllerBase { private readonly IGlobalResourcePublicAppService _globalResourcePublicAppService; private readonly IDistributedCache _resourceCache; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs index c73fba95e7..67a9d64f67 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs @@ -7,7 +7,7 @@ using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection; namespace Volo.CmsKit.Public.Web.Controllers; -public class CmsKitPublicWidgetsController : AbpController +public class CmsKitPublicWidgetsController : CmsKitPublicControllerBase { public Task ReactionSelection(string entityType, string entityId) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs index b1ea42397f..5810103ea9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs @@ -76,24 +76,33 @@ public class CommentingViewComponent : AbpViewComponent LoginUrl = loginUrl, Comments = comments.OrderByDescending(i => i.CreationTime).ToList() }; + await ConvertMarkdownTextsToHtml(viewModel); if (CmsKitCommentOptions.IsRecaptchaEnabled) { - CaptchaOutput = SimpleMathsCaptchaGenerator.Generate(new CaptchaOptions( - number1MinValue: 1, - number1MaxValue: 10, - number2MinValue: 5, - number2MaxValue: 15) - ); + CaptchaOutput = await GenerateCaptchaAsync(); viewModel.CaptchaImageBase64 = GetCaptchaImageBase64(CaptchaOutput.ImageBytes); } + this.Input = viewModel; return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", this); } - private string GetCaptchaImageBase64(byte[] bytes) + public async Task GenerateCaptchaAsync() + { + return await SimpleMathsCaptchaGenerator.GenerateAsync( + new CaptchaOptions( + number1MinValue: 1, + number1MaxValue: 10, + number2MinValue: 5, + number2MaxValue: 15 + ) + ); + } + + public string GetCaptchaImageBase64(byte[] bytes) { return $"data:image/jpg;base64,{Convert.ToBase64String(bytes)}"; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml index 34ce468187..d4e09e9b61 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml @@ -39,7 +39,7 @@
- @L["MarkdownSupported"] + @L["MarkdownSupported"]
@if (CmsKitCommentOptions.Value.IsRecaptchaEnabled) @@ -127,15 +127,33 @@ +
+ @L["MarkdownSupported"] +
+ + @if (CmsKitCommentOptions.Value.IsRecaptchaEnabled) + { + var output = await Model.GenerateCaptchaAsync(); + +
+ +
+
+ +
+
+ +
+ +
+
+ }
@L["Update"] @L["Cancel"]
-
- @L["MarkdownSupported"] -
diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js index c5c26672f1..75f3288982 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js @@ -111,14 +111,23 @@ $form.submit(function (e) { e.preventDefault(); let formAsObject = $form.serializeFormToObject(); - volo.cmsKit.public.comments.commentPublic.update( - formAsObject.id, - { + $.ajax({ + type: 'POST', + url: '/CmsKitPublicComments/Update/' + formAsObject.id, + contentType: 'application/json; charset=utf-8', + dataType: 'json', + data: JSON.stringify({ text: formAsObject.commentText, - concurrencyStamp: formAsObject.commentConcurrencyStamp + concurrencyStamp: formAsObject.commentConcurrencyStamp, + captchaToken: formAsObject.captchaId, + captchaAnswer: formAsObject.input?.captcha + }), + success: function () { + widgetManager.refresh($widget); + }, + error: function (data) { + abp.message.error(data.responseJSON.error.message); } - ).then(function () { - widgetManager.refresh($widget); }); }); }); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs index 75f08f724f..5fec9e7cdb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs @@ -1,4 +1,5 @@ -using SixLabors.Fonts; +using System; +using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; @@ -47,6 +48,8 @@ public class CaptchaOptions public int Number2MaxValue { get; set; } = 99; + public TimeSpan DurationOfValidity { get; set; } = TimeSpan.FromMinutes(10); + public CaptchaOptions() { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs index 220e24f892..bd7f9f0371 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; @@ -15,27 +14,30 @@ using Microsoft.Extensions.Localization; using Volo.Abp.DependencyInjection; using Color = SixLabors.ImageSharp.Color; using PointF = SixLabors.ImageSharp.PointF; +using Volo.Abp.Caching; +using Microsoft.Extensions.Caching.Distributed; namespace Volo.CmsKit.Public.Web.Security.Captcha; -public class SimpleMathsCaptchaGenerator : ISingletonDependency +public class SimpleMathsCaptchaGenerator : ITransientDependency { - private readonly IStringLocalizer _localizer; + protected IStringLocalizer Localizer { get; } + protected IDistributedCache Cache { get; } - public SimpleMathsCaptchaGenerator(IStringLocalizer localizer) + public SimpleMathsCaptchaGenerator(IStringLocalizer localizer, IDistributedCache cache) { - _localizer = localizer; + Localizer = localizer; + Cache = cache; } - private static Dictionary Session { get; set; } = new Dictionary(); - public CaptchaOutput Generate() + public virtual Task GenerateAsync() { - return Generate(options: null, number1: null, number2: null); + return GenerateAsync(options: null, number1: null, number2: null); } - public CaptchaOutput Generate(CaptchaOptions options) + public virtual Task GenerateAsync(CaptchaOptions options) { - return Generate(options, number1: null, number2: null); + return GenerateAsync(options, number1: null, number2: null); } /// @@ -45,7 +47,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency /// First number for maths operation /// Second number for maths operation /// - public CaptchaOutput Generate(CaptchaOptions options, int? number1, int? number2) + public virtual async Task GenerateAsync(CaptchaOptions options, int? number1, int? number2) { var random = new Random(); options ??= new CaptchaOptions(); @@ -65,11 +67,15 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency { Text = text, Result = Calculate(number1.Value, number2.Value), - ImageBytes = GenerateInternal(text, options) + ImageBytes = GenerateInternal(text, options) } }; - Session[request.Output.Id] = request; + await Cache.SetAsync(request.Output.Id.ToString("N"), request.Output, new DistributedCacheEntryOptions + { + AbsoluteExpiration = DateTimeOffset.Now.Add(options.DurationOfValidity) + }); + return request.Output; } @@ -78,24 +84,25 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency return number1 + number2; } - public void Validate(Guid requestId, int value) + public virtual async Task ValidateAsync(Guid requestId, int value) { - var request = Session[requestId]; - if (request.Output.Result != value) + var request = await Cache.GetAsync(requestId.ToString("N")); + + if(request == null || request.Result != value) { - throw new UserFriendlyException(_localizer["CaptchaCodeErrorMessage"]); + throw new UserFriendlyException(Localizer["CaptchaCodeErrorMessage"]); } } - public void Validate(Guid requestId, string value) + public virtual async Task ValidateAsync(Guid requestId, string value) { if (int.TryParse(value, out var captchaInput)) { - Validate(requestId, captchaInput); + await ValidateAsync(requestId, captchaInput); } else { - throw new UserFriendlyException(_localizer["CaptchaCodeMissingMessage"]); + throw new UserFriendlyException(Localizer["CaptchaCodeMissingMessage"]); } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs index 30ebf9a96f..c0a5b1295f 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs @@ -143,6 +143,27 @@ namespace Volo.Docs.Documents.FullSearch.Elastic CancellationToken cancellationToken = default) { ValidateElasticSearchEnabled(); + + FieldNameQueryBase query; + // if context starts with " or ends with " then we search for exact match + if (context.StartsWith("\"") && context.EndsWith("\"")) + { + context = context.Trim('"'); + + query = new MatchPhraseQuery + { + Query = context + }; + } + else + { + query = new MatchQuery + { + Query = context + }; + } + + query.Field = "content"; var request = new SearchRequest { @@ -152,11 +173,7 @@ namespace Volo.Docs.Documents.FullSearch.Elastic { Must = new QueryContainer[] { - new MatchQuery - { - Field = "content", - Query = context - } + query, }, Filter = new QueryContainer[] { diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 737bc2fe36..4898baf215 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -6,6 +6,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Localization; @@ -108,6 +109,12 @@ namespace Volo.Docs.Pages.Documents.Project public virtual async Task OnGetAsync() { + var displayUrl = Request.GetDisplayUrl(); + var decodedUrl = HttpUtility.UrlDecode(displayUrl); + if (decodedUrl != displayUrl) + { + return Redirect(decodedUrl); + } try { return await SetPageAsync(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Microsoft/Extensions/DependencyInjection/OpenIddictServerBuilderExtensions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Microsoft/Extensions/DependencyInjection/OpenIddictServerBuilderExtensions.cs new file mode 100644 index 0000000000..c99ce5e245 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Microsoft/Extensions/DependencyInjection/OpenIddictServerBuilderExtensions.cs @@ -0,0 +1,20 @@ +using System.IO; +using System.Security.Cryptography.X509Certificates; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class OpenIddictServerBuilderExtensions +{ + public static OpenIddictServerBuilder AddProductionEncryptionAndSigningCertificate(this OpenIddictServerBuilder builder, string fileName, string passPhrase) + { + if (!File.Exists(fileName)) + { + throw new FileNotFoundException($"Signing Certificate couldn't found: {fileName}"); + } + + var certificate = new X509Certificate2(fileName, passPhrase); + builder.AddSigningCertificate(certificate); + builder.AddEncryptionCertificate(certificate); + return builder; + } +} diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index d49d6b5375..bbcda3d38e 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -108,9 +108,9 @@ "eslint-config-prettier": "8.1.0", "eslint-plugin-cypress": "^2.10.3", "got": "^11.5.2", - "jest": "29.4.3", + "jest": "^29.0.0", "jest-canvas-mock": "^2.3.1", - "jest-environment-jsdom": "29.4.3", + "jest-environment-jsdom": "^29.0.0", "jest-preset-angular": "13.1.0", "jsonc-eslint-parser": "^2.1.0", "jsonc-parser": "^2.3.0", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj index c532ed66a7..43bfef36f3 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj @@ -90,6 +90,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs index e088b4a84f..faf7121dfc 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs @@ -46,6 +46,7 @@ using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.Blazor.Server; using Volo.Abp.TenantManagement.MongoDB; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Uow; @@ -111,6 +112,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -119,15 +123,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index 8069d64ba1..b90b243add 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -98,6 +98,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs index b0953ae2eb..d73ba01a49 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs @@ -48,6 +48,7 @@ using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.Blazor.Server; using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Validation.Localization; @@ -113,6 +114,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -121,15 +125,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj index 0f2017bc4a..05e9c4c61a 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj @@ -86,6 +86,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs index ca98281863..f5160169d4 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs @@ -40,6 +40,7 @@ using Volo.Abp.SettingManagement.MongoDB; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.MongoDB; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Uow; using Volo.Abp.VirtualFileSystem; @@ -99,6 +100,9 @@ public class MyProjectNameHostModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -106,15 +110,28 @@ public class MyProjectNameHostModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj index 24b18c1e8b..88c4e51db6 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj @@ -94,6 +94,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs index 000fbd1e38..b76933ce94 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs @@ -42,6 +42,7 @@ using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Uow; using Volo.Abp.VirtualFileSystem; @@ -102,6 +103,9 @@ public class MyProjectNameHostModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -109,15 +113,28 @@ public class MyProjectNameHostModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj index 1453b82848..0c8b18bcef 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj @@ -82,6 +82,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs index 400e865d1d..7a99e10635 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs @@ -40,6 +40,7 @@ using Volo.Abp.SettingManagement.MongoDB; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.MongoDB; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Uow; using Volo.Abp.Validation.Localization; @@ -100,6 +101,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -107,15 +111,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj index 817ab98cde..e12f10ec2c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj @@ -90,6 +90,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs index 792e93fe86..6705902ed4 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs @@ -43,6 +43,7 @@ using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -103,6 +104,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -110,15 +114,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj index 0d374b477d..64ac6883ee 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj @@ -85,6 +85,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs index f097d8d434..6e702fd36c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs @@ -42,6 +42,7 @@ using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.MongoDB; using Volo.Abp.TenantManagement.Web; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Uow; @@ -106,6 +107,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -113,15 +117,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj index 71f3f1b1fb..c9c96a9944 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj @@ -93,6 +93,13 @@ + + + + Always + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs index 8b661a5d76..43c60fc6a7 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs @@ -44,6 +44,7 @@ using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.EntityFrameworkCore; using Volo.Abp.TenantManagement.Web; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.Validation.Localization; @@ -108,6 +109,9 @@ public class MyProjectNameModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -115,15 +119,28 @@ public class MyProjectNameModule : AbpModule ); }); - PreConfigure(builder => - { - builder.AddValidation(options => - { - options.AddAudiences("MyProjectName"); - options.UseLocalServer(); - options.UseAspNetCore(); - }); - }); + PreConfigure(builder => + { + builder.AddValidation(options => + { + options.AddAudiences("MyProjectName"); + options.UseLocalServer(); + options.UseAspNetCore(); + }); + }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj index 75be19812e..0de7423714 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj @@ -31,6 +31,13 @@ + + + + Always + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs index b044af0d06..104fe9fed6 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs @@ -31,6 +31,7 @@ using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.DistributedLocking; using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.UI; using Volo.Abp.VirtualFileSystem; @@ -52,6 +53,9 @@ public class MyProjectNameAuthServerModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + PreConfigure(builder => { builder.AddValidation(options => @@ -61,6 +65,19 @@ public class MyProjectNameAuthServerModule : AbpModule options.UseAspNetCore(); }); }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index a7429d100a..b03010ada9 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -45,6 +45,13 @@ + + + + Always + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs index 758b60f74e..e13c32cbf4 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs @@ -37,6 +37,7 @@ using Volo.Abp.Modularity; using Volo.Abp.SettingManagement.Blazor.Server; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement.Blazor.Server; +using Volo.Abp.OpenIddict; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; @@ -62,6 +63,9 @@ public class MyProjectNameBlazorModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -83,6 +87,19 @@ public class MyProjectNameBlazorModule : AbpModule options.UseAspNetCore(); }); }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj index 989e9e585c..c9231c1e0e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj @@ -31,6 +31,13 @@ + + + + Always + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs index 18863a59ff..f9c8d6a1c2 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs @@ -33,6 +33,7 @@ using Volo.Abp.PermissionManagement.Web; using Volo.Abp.SettingManagement.Web; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement.Web; +using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; @@ -57,6 +58,9 @@ public class MyProjectNameWebModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.PreConfigure(options => { options.AddAssemblyResource( @@ -78,6 +82,19 @@ public class MyProjectNameWebModule : AbpModule options.UseAspNetCore(); }); }); + + if (!hostingEnvironment.IsDevelopment()) + { + PreConfigure(options => + { + options.AddDevelopmentEncryptionAndSigningCertificate = false; + }); + + PreConfigure(serverBuilder => + { + serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "00000000-0000-0000-0000-000000000000"); + }); + } } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs index d038106f5a..f6c290ef6d 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs @@ -1,23 +1,15 @@ -using System; -using System.Net; +using System.Net; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; using Shouldly; +using Volo.Abp.AspNetCore; using Volo.Abp.AspNetCore.TestBase; namespace MyCompanyName.MyProjectName; -public abstract class MyProjectNameWebTestBase : AbpAspNetCoreIntegratedTestBase +public abstract class MyProjectNameWebTestBase : AbpWebApplicationFactoryIntegratedTest { - protected override IHostBuilder CreateHostBuilder() - { - return base - .CreateHostBuilder() - .UseContentRoot(WebContentDirectoryFinder.CalculateContentRootFolder() ?? throw new InvalidOperationException()); - } - protected virtual async Task GetResponseAsObjectAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/Program.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/Program.cs new file mode 100644 index 0000000000..f4c388685f --- /dev/null +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/Program.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Builder; +using MyCompanyName.MyProjectName; +using Volo.Abp.AspNetCore.TestBase; + +var builder = WebApplication.CreateBuilder(); +await builder.RunAbpModuleAsync(); + +public partial class Program +{ +}