diff --git a/docs/en/AspNet-Boilerplate-Migration-Guide.md b/docs/en/AspNet-Boilerplate-Migration-Guide.md index c7cc8a9e53..f4c2ec712b 100644 --- a/docs/en/AspNet-Boilerplate-Migration-Guide.md +++ b/docs/en/AspNet-Boilerplate-Migration-Guide.md @@ -438,7 +438,7 @@ ABP Framework uses and extends ASP.NET Core's [distributed caching abstraction]( ### Logging -ASP.NET Boilerplate uses Castle Windsor's [logging facility](http://docs.castleproject.org/Windsor.Logging-Facility.ashx) as an abstraction and supports multiple logging providers including Log4Net (the default one comes with the startup projects) and Serilog. You typically property-inject the logger: +ASP.NET Boilerplate uses Castle Windsor's [logging facility](https://github.com/castleproject/Windsor/blob/master/docs/logging-facility.md) as an abstraction and supports multiple logging providers including Log4Net (the default one comes with the startup projects) and Serilog. You typically property-inject the logger: ````csharp using Castle.Core.Logging; //1: Import Logging namespace diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 158466d153..bceca3548f 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -406,5 +406,5 @@ This is already done for the startup template integration tests. ## See Also * [Permission Management Module](Modules/Permission-Management.md) -* [ASP.NET Core MVC / Razor Pages JavaScript Auth API](API/JavaScript-API/Auth.md) +* [ASP.NET Core MVC / Razor Pages JavaScript Auth API](UI/AspNetCore/JavaScript-API/Auth.md) * [Permission Management in Angular UI](UI/Angular/Permission-Management.md) diff --git a/docs/en/CSRF-Anti-Forgery.md b/docs/en/CSRF-Anti-Forgery.md index 33b856f563..720edc5924 100644 --- a/docs/en/CSRF-Anti-Forgery.md +++ b/docs/en/CSRF-Anti-Forgery.md @@ -25,7 +25,7 @@ ABP Framework provides `[AbpValidateAntiForgeryToken]` and `[AbpAutoValidateAnti ABP Framework also automates the following infrastructure; -* Server side sets a **special cookie**, named `XSRF-TOKEN` by default, that is used make the antiforgery token value available to the browser. This is **done automatically** (by the [application configuration](Application-Configuration.md) endpoint). Nothing to do in the client side. +* Server side sets a **special cookie**, named `XSRF-TOKEN` by default, that is used make the antiforgery token value available to the browser. This is **done automatically** (by the [application configuration](API/Application-Configuration.md) endpoint). Nothing to do in the client side. * In the client side, it reads the token from the cookie and sends it in the **HTTP header** (named `RequestVerificationToken` by default). This is implemented for all the supported UI types. * Server side validates the antiforgery token **only for same and cross site requests** made by the browser. It bypasses the validation for non-browser clients. diff --git a/docs/en/Contribution/Index.md b/docs/en/Contribution/Index.md index 83ec0bf05d..d245ccabcf 100644 --- a/docs/en/Contribution/Index.md +++ b/docs/en/Contribution/Index.md @@ -26,7 +26,7 @@ If you have a feature idea for the framework or modules, [create an issue](https ## Document Translation -You may want to translate the complete [documentation](https://abp.io/documents/) (including this one) to your mother language. If so, follow these steps: +You may want to translate the complete [documentation](https://docs.abp.io) (including this one) to your mother language. If so, follow these steps: * Clone the [ABP repository](https://github.com/abpframework/abp/) from Github. * To add a new language, create a new folder inside the [docs](https://github.com/abpframework/abp/tree/master/docs) folder. Folder names can be "en", "es", "fr", "tr" and so on based on the language (see [all culture codes](https://msdn.microsoft.com/en-us/library/hh441729.aspx)). diff --git a/docs/en/Getting-Started-React-Native.md b/docs/en/Getting-Started-React-Native.md index a06257fec9..08faac3608 100644 --- a/docs/en/Getting-Started-React-Native.md +++ b/docs/en/Getting-Started-React-Native.md @@ -27,13 +27,13 @@ You have multiple options to initiate a new React Native project that works with ### 1. Using ABP CLI -ABP CLI is probably the most convenient and flexible way to initiate an ABP solution with a React Native application. Simply [install the ABP CLI](../../CLI.md) and run the following command in your terminal: +ABP CLI is probably the most convenient and flexible way to initiate an ABP solution with a React Native application. Simply [install the ABP CLI](CLI.md) and run the following command in your terminal: ```shell abp new MyCompanyName.MyProjectName -csf -u -m react-native ``` -> To see further options in the CLI, please visit the [CLI manual](../../CLI.md). +> To see further options in the CLI, please visit the [CLI manual](CLI.md). This command will prepare a solution with an **Angular** or an **MVC** (depends on your choice), a **.NET Core**, and a **React Native** project in it. diff --git a/docs/en/Migration-Guides/Abp-4_0.md b/docs/en/Migration-Guides/Abp-4_0.md index 33ccc63513..9e1bd4e816 100644 --- a/docs/en/Migration-Guides/Abp-4_0.md +++ b/docs/en/Migration-Guides/Abp-4_0.md @@ -244,13 +244,28 @@ public class MyService : ITransientDependency public async Task DoItAsync() { await _options.SetAsync(); - + var requiredLength = _options.Value.Password.RequiredLength; } } ```` Pre-built modules already handles this. However, if you have used `IdentityOptions` directly in your code, you also need to follow this new pattern. +Please make sure that the injected `IOptions` service and the service consuming it are in the same scope of dependency injection container. + +### LDAP module full async + +In order to solve the problem of async over sync, `ILdapManager` uses async method instead of sync. And use [`ldap4net`](https://github.com/flamencist/ldap4net) to replace [`Novell.Directory.Ldap.NETStandard`](https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard) package. + +### Dynamic external login provider system + +You need to change the `WithDynamicOptions` method and pass the `Handler` class of the external login provider. +Use the `goto definition` function in Visual Studio or Rider to check `Handler` in the extension method like `AddGoogle`. + +```csharp +- WithDynamicOptions() ++ WithDynamicOptions() +```` ## ASP.NET Core MVC / Razor Pages UI @@ -262,4 +277,4 @@ See the [Angular UI Migration Guide](Abp-4_0-Angular.md). ## Blazor UI -See the [Blazor UI Migration Guide](Abp-4_0-Blazor.md). \ No newline at end of file +See the [Blazor UI Migration Guide](Abp-4_0-Blazor.md). diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md index e788a4c0f8..5780b4b827 100644 --- a/docs/en/Modules/Docs.md +++ b/docs/en/Modules/Docs.md @@ -446,7 +446,7 @@ As an example you can see ABP Framework documentation: #### Conditional sections feature (Using Scriban) -Docs module uses [Scriban]( ) for conditionally show or hide some parts of a document. In order to use that feature, you have to create a JSON file as **Parameter document** per every language. It will contain all the key-values, as well as their display names. +Docs module uses [Scriban](https://github.com/lunet-io/scriban/tree/master/doc) for conditionally show or hide some parts of a document. In order to use that feature, you have to create a JSON file as **Parameter document** per every language. It will contain all the key-values, as well as their display names. For example, [en/docs-params.json](https://github.com/abpio/abp-commercial-docs/blob/master/en/docs-params.json): @@ -537,7 +537,7 @@ Also, **Document_Language_Code** and **Document_Version** keys are pre-defined i ------ -**IMPORTANT NOTICE**: Scriban uses "{{" and "}}" for syntax. Therefore, you must use escape blocks if you are going to use those in your document (an Angular document, for example). See [Scriban docs]( ) for more information. +**IMPORTANT NOTICE**: Scriban uses "{{" and "}}" for syntax. Therefore, you must use escape blocks if you are going to use those in your document (an Angular document, for example). See [Scriban docs](https://github.com/lunet-io/scriban/blob/master/doc/language.md#13-escape-block) for more information. ### 8- Creating the Navigation Document diff --git a/docs/en/Startup-Templates/Application.md b/docs/en/Startup-Templates/Application.md index 8cccf32382..81f0170e59 100644 --- a/docs/en/Startup-Templates/Application.md +++ b/docs/en/Startup-Templates/Application.md @@ -97,7 +97,7 @@ A `BookType` enum and a `BookConsts` class (which may have some constant fields #### .Domain Project -This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), [value types](../Value-Types.md), [repository interfaces](../Repositories.md) and other domain objects. +This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), [value objects](../Value-Objects.md), [repository interfaces](../Repositories.md) and other domain objects. A `Book` entity, a `BookManager` domain service and an `IBookRepository` interface are good candidates for this project. diff --git a/docs/en/UI/AspNetCore/Data-Tables.md b/docs/en/UI/AspNetCore/Data-Tables.md index 79fd6a3be1..a9dbf1eecf 100644 --- a/docs/en/UI/AspNetCore/Data-Tables.md +++ b/docs/en/UI/AspNetCore/Data-Tables.md @@ -101,7 +101,7 @@ Here, the all configuration options; DataTables.Net has its own expected data format while getting results of an AJAX call to the server to get the table data. They are especially related how paging and sorting parameters are sent and received. ABP Framework also offers its own conventions for the client-server [AJAX](JavaScript-API/Ajax.md) communication. -The `abp.libs.datatables.createAjax` method (used in the example above) adapts request and response data format and perfectly works with the [Dynamic JavaScript Client Proxy](Dynamic-JavaScript-Client-Proxies.md) system. +The `abp.libs.datatables.createAjax` method (used in the example above) adapts request and response data format and perfectly works with the [Dynamic JavaScript Client Proxy](Dynamic-JavaScript-Proxies.md) system. This works automatically, so most of the times you don't need to know how it works. See the [DTO document](../../Data-Transfer-Objects.md) if you want to learn more about `IPagedAndSortedResultRequest`, `IPagedResult` and other standard interfaces and base DTO classes those are used in client to server communication. diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index 762d6a4b0b..7a8fe31e3e 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -109,7 +109,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt As seen above, a menu contributor contributes to the menu dynamically. So, you can perform any custom logic or get menu items from any source. -One use case is the [authorization](Authorization.md). You typically want to add menu items by checking a permission. +One use case is the [authorization](../../Authorization.md). You typically want to add menu items by checking a permission. **Example: Check if the current user has a permission** diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Index.md b/docs/en/UI/AspNetCore/Tag-Helpers/Index.md index f85edb5142..5b16d9ccdc 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Index.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Index.md @@ -16,7 +16,7 @@ Here, the list of components those are wrapped by the ABP Framework: * [Badges](Badges.md) * [Blockquote](Blockquote.md) * [Borders](Borders.md) -* [Breadcrumb](Breadcrumb.md) +* [Breadcrumb](Breadcrumbs.md) * [Buttons](Buttons.md) * [Cards](Cards.md) * [Carousel](Carousel.md) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs index 2a8c48b1c5..e83e240c85 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs @@ -23,15 +23,13 @@ namespace Microsoft.AspNetCore.RequestLocalization public async Task InvokeAsync(HttpContext context, RequestDelegate next) { + var middleware = new RequestLocalizationMiddleware( next, - new OptionsWrapper( - await _requestLocalizationOptionsProvider.GetLocalizationOptionsAsync() -), - _loggerFactory + new OptionsWrapper(await _requestLocalizationOptionsProvider.GetLocalizationOptionsAsync()), _loggerFactory ); await middleware.Invoke(context); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsFactory.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsFactory.cs deleted file mode 100644 index 10cce6a776..0000000000 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Options; -using Volo.Abp.Options; - -namespace Microsoft.AspNetCore.RequestLocalization -{ - public class AbpRequestLocalizationOptionsFactory : AbpOptionsFactory - { - private readonly IAbpRequestLocalizationOptionsProvider _abpRequestLocalizationOptionsProvider; - - public AbpRequestLocalizationOptionsFactory( - IAbpRequestLocalizationOptionsProvider abpRequestLocalizationOptionsProvider, - IEnumerable> setups, - IEnumerable> postConfigures) - : base( - setups, - postConfigures) - { - _abpRequestLocalizationOptionsProvider = abpRequestLocalizationOptionsProvider; - } - - public override RequestLocalizationOptions Create(string name) - { - return _abpRequestLocalizationOptionsProvider.GetLocalizationOptions(); - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsManager.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsManager.cs new file mode 100644 index 0000000000..3748e6ff6c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationOptionsManager.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Options; +using Volo.Abp.Options; + +namespace Microsoft.AspNetCore.RequestLocalization +{ + public class AbpRequestLocalizationOptionsManager : AbpDynamicOptionsManager + { + private RequestLocalizationOptions _options; + + private readonly IAbpRequestLocalizationOptionsProvider _abpRequestLocalizationOptionsProvider; + + public AbpRequestLocalizationOptionsManager( + IOptionsFactory factory, + IAbpRequestLocalizationOptionsProvider abpRequestLocalizationOptionsProvider) + : base(factory) + { + _abpRequestLocalizationOptionsProvider = abpRequestLocalizationOptionsProvider; + } + + public override RequestLocalizationOptions Get(string name) + { + return _options ?? base.Get(name); + } + + protected override async Task OverrideOptionsAsync(string name, RequestLocalizationOptions options) + { + _options = await _abpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs index 7d1c643221..f416ac6f61 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs @@ -10,7 +10,6 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization; using Volo.Abp.Settings; -using Volo.Abp.Threading; namespace Microsoft.AspNetCore.RequestLocalization { @@ -32,16 +31,6 @@ namespace Microsoft.AspNetCore.RequestLocalization _optionsAction = optionsAction; } - public RequestLocalizationOptions GetLocalizationOptions() - { - if (_requestLocalizationOptions != null) - { - return _requestLocalizationOptions; - } - - return AsyncHelper.RunSync(GetLocalizationOptionsAsync); - } - public async Task GetLocalizationOptionsAsync() { if (_requestLocalizationOptions == null) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs index cb4daec7f2..aea718b7cb 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs @@ -8,8 +8,6 @@ namespace Microsoft.AspNetCore.RequestLocalization { void InitLocalizationOptions(Action optionsAction = null); - RequestLocalizationOptions GetLocalizationOptions(); - Task GetLocalizationOptionsAsync(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs index fad534949d..c97c3787e7 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs @@ -38,7 +38,7 @@ namespace Volo.Abp.AspNetCore AddAspNetServices(context.Services); context.Services.AddObjectAccessor(); - context.Services.Replace(ServiceDescriptor.Transient, AbpRequestLocalizationOptionsFactory>()); + context.Services.AddAbpDynamicOptions(); } private static void AddAspNetServices(IServiceCollection services) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpDynamicOptionsManager.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpDynamicOptionsManager.cs index af40ff1825..43d98aead4 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpDynamicOptionsManager.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpDynamicOptionsManager.cs @@ -16,9 +16,9 @@ namespace Volo.Abp.Options public virtual Task SetAsync(string name) { - return OverrideOptionsAsync(base.Get(name)); + return OverrideOptionsAsync(name, base.Get(name)); } - protected abstract Task OverrideOptionsAsync(T options); + protected abstract Task OverrideOptionsAsync(string name, T options); } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpOptionsFactory.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpOptionsFactory.cs index ecbe0d8271..e2a7a7bf53 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpOptionsFactory.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpOptionsFactory.cs @@ -4,21 +4,44 @@ using Microsoft.Extensions.Options; namespace Volo.Abp.Options { //TODO: Derive from OptionsFactory when this is released: https://github.com/aspnet/Options/pull/258 (or completely remove this!) + // https://github.com/dotnet/runtime/blob/master/src/libraries/Microsoft.Extensions.Options/src/OptionsFactory.cs public class AbpOptionsFactory : IOptionsFactory where TOptions : class, new() { private readonly IEnumerable> _setups; private readonly IEnumerable> _postConfigures; + private readonly IEnumerable> _validations; - public AbpOptionsFactory(IEnumerable> setups, IEnumerable> postConfigures) + public AbpOptionsFactory( + IEnumerable> setups, + IEnumerable> postConfigures) + : this(setups, postConfigures, validations: null) + { + + } + + public AbpOptionsFactory( + IEnumerable> setups, + IEnumerable> postConfigures, + IEnumerable> validations) { _setups = setups; _postConfigures = postConfigures; + _validations = validations; } public virtual TOptions Create(string name) { var options = new TOptions(); + ConfigureOptions(name, options); + PostConfigureOptions(name, options); + ValidateOptions(name, options); + + return options; + } + + protected virtual void ConfigureOptions(string name, TOptions options) + { foreach (var setup in _setups) { if (setup is IConfigureNamedOptions namedSetup) @@ -30,13 +53,34 @@ namespace Volo.Abp.Options setup.Configure(options); } } + } + protected virtual void PostConfigureOptions(string name, TOptions options) + { foreach (var post in _postConfigures) { post.PostConfigure(name, options); } + } - return options; + protected virtual void ValidateOptions(string name, TOptions options) + { + if (_validations != null) + { + var failures = new List(); + foreach (var validate in _validations) + { + var result = validate.Validate(name, options); + if (result.Failed) + { + failures.AddRange(result.Failures); + } + } + if (failures.Count > 0) + { + throw new OptionsValidationException(name, typeof(TOptions), failures); + } + } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj index 277ac1c24b..584c3e74c0 100644 --- a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj +++ b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsManager.cs similarity index 61% rename from framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs rename to framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsManager.cs index 9579e169be..57d13693b4 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsManager.cs @@ -1,36 +1,22 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.Options; using Volo.Abp.Settings; -using Volo.Abp.Threading; namespace Volo.Abp.Ldap { - public class AbpAbpLdapOptionsFactory : AbpOptionsFactory + public class AbpAbpLdapOptionsManager : AbpDynamicOptionsManager { protected ISettingProvider SettingProvider { get; } - public AbpAbpLdapOptionsFactory( - IEnumerable> setups, - IEnumerable> postConfigures, - ISettingProvider settingProvider) - : base(setups, postConfigures) + public AbpAbpLdapOptionsManager(IOptionsFactory factory, ISettingProvider settingProvider) + : base(factory) { SettingProvider = settingProvider; } - public override AbpLdapOptions Create(string name) - { - var options = base.Create(name); - - AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); - - return options; - } - - protected virtual async Task OverrideOptionsAsync(AbpLdapOptions options) + protected override async Task OverrideOptionsAsync(string name, AbpLdapOptions options) { options.ServerHost = await GetSettingOrDefaultValue(LdapSettingNames.ServerHost, options.ServerHost); options.ServerPort = await SettingProvider.GetAsync(LdapSettingNames.ServerPort, options.ServerPort); diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs index c842d4d76b..3366f3d70f 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs @@ -18,8 +18,7 @@ namespace Volo.Abp.Ldap { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.Replace(ServiceDescriptor.Transient, AbpAbpLdapOptionsFactory>()); - context.Services.Replace(ServiceDescriptor.Scoped, OptionsManager>()); + context.Services.AddAbpDynamicOptions(); var configuration = context.Services.GetConfiguration(); var ldapConfiguration = configuration["Ldap"]; diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs index 6ad66b0cb3..2d41724c88 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs @@ -1,7 +1,9 @@ -namespace Volo.Abp.Ldap +using System.Threading.Tasks; + +namespace Volo.Abp.Ldap { public interface ILdapManager { - bool Authenticate(string username, string password); + Task AuthenticateAsync(string username, string password); } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs index 2d890c10f7..7a8d06746a 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs @@ -1,6 +1,8 @@ using System; +using System.Threading.Tasks; +using LdapForNet; +using LdapForNet.Native; using Microsoft.Extensions.Options; -using Novell.Directory.Ldap; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.DependencyInjection; @@ -15,17 +17,16 @@ namespace Volo.Abp.Ldap public LdapManager(IOptions ldapSettingsOptions) { LdapOptions = ldapSettingsOptions.Value; - Logger = NullLogger.Instance; } - public bool Authenticate(string username, string password) + public virtual async Task AuthenticateAsync(string username, string password) { try { - using (var conn = CreateLdapConnection()) + using (var conn = await CreateLdapConnectionAsync()) { - AuthenticateLdapConnection(conn, username, password); + await AuthenticateLdapConnectionAsync(conn, username, password); return true; } } @@ -36,22 +37,33 @@ namespace Volo.Abp.Ldap } } - protected virtual ILdapConnection CreateLdapConnection() + protected virtual async Task CreateLdapConnectionAsync() { var ldapConnection = new LdapConnection(); - ConfigureLdapConnection(ldapConnection); - ldapConnection.Connect(LdapOptions.ServerHost, LdapOptions.ServerPort); + await ConfigureLdapConnectionAsync(ldapConnection); + await ConnectAsync(ldapConnection); return ldapConnection; } - protected virtual void ConfigureLdapConnection(ILdapConnection connection) + protected virtual Task ConfigureLdapConnectionAsync(ILdapConnection ldapConnection) { + return Task.CompletedTask; + } + protected virtual Task ConnectAsync(ILdapConnection ldapConnection) + { + ldapConnection.Connect(LdapOptions.ServerHost, LdapOptions.ServerPort); + + return Task.CompletedTask; } - protected virtual void AuthenticateLdapConnection(ILdapConnection connection, string username, string password) + protected virtual async Task AuthenticateLdapConnectionAsync(ILdapConnection connection, string username, string password) { - connection.Bind(username, password); + await connection.BindAsync(Native.LdapAuthType.Simple, new LdapCredential() + { + UserName = username, + Password = password + }); } } } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs index 8da9a9303d..6cc3a0acc7 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using System.Threading.Tasks; +using Shouldly; using Volo.Abp.Testing; using Xunit; @@ -19,10 +20,11 @@ namespace Volo.Abp.Ldap } [Fact(Skip = "Required Ldap environment")] - public void Authenticate() + public async Task AuthenticateAsync() { - _ldapManager.Authenticate("cn=abp,dc=abp,dc=io", "123qwe").ShouldBe(true); - _ldapManager.Authenticate("NoExists", "123qwe").ShouldBe(false); + (await _ldapManager.AuthenticateAsync("cn=abp,dc=abp,dc=io", "123qwe")).ShouldBe(true); + (await _ldapManager.AuthenticateAsync("cn=abp,dc=abp,dc=io", "123123")).ShouldBe(false); + (await _ldapManager.AuthenticateAsync("NoExists", "123qwe")).ShouldBe(false); } } } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs index 8ec7ef94c6..d6e6e1fc29 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.Ldap [Fact] public void Should_Resolve_AbpAbpLdapOptionsFactory() { - GetRequiredService>().ShouldBeOfType(typeof(AbpAbpLdapOptionsFactory)); + GetRequiredService>().ShouldBeOfType(typeof(AbpAbpLdapOptionsManager)); } } } diff --git a/modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs b/modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs index 600cc05f84..c41beef251 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs +++ b/modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs @@ -166,7 +166,7 @@ namespace Volo.BloggingTestApp app.UseAuthentication(); - app.UseRequestLocalization(app.ApplicationServices.GetRequiredService>().Value); + app.UseAbpRequestLocalization(); app.UseConfiguredEndpoints(); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsManager.cs index 5735f36051..8ff4c141eb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsManager.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Identity SettingProvider = settingProvider; } - protected override async Task OverrideOptionsAsync(IdentityOptions options) + protected override async Task OverrideOptionsAsync(string name, IdentityOptions options) { options.Password.RequiredLength = await SettingProvider.GetAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength); options.Password.RequiredUniqueChars = await SettingProvider.GetAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars);