Browse Source

Merge branch 'dev' into maliming/system.text.json

pull/5952/head
maliming 6 years ago
parent
commit
998908765e
  1. 1
      .gitignore
  2. 2
      docs/en/API/Dynamic-CSharp-API-Clients.md
  3. 6
      docs/en/Application-Services.md
  4. 4
      docs/en/Authorization.md
  5. 2
      docs/en/Background-Workers-Quartz.md
  6. 2
      docs/en/Background-Workers.md
  7. 8
      docs/en/Blog-Posts/2020-05-08 v2_7_Release/Post.md
  8. 8
      docs/en/Community-Articles/2020-04-19-Customize-the-SignIn-Manager/POST.md
  9. 14
      docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md
  10. 46
      docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/POST.md
  11. BIN
      docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/add-to-languages.png
  12. BIN
      docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/database-table.png
  13. BIN
      docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/language-target.png
  14. BIN
      docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/website-new-language.png
  15. 42
      docs/en/Customizing-Application-Modules-Overriding-Services.md
  16. 6
      docs/en/Domain-Driven-Design.md
  17. 4
      docs/en/Domain-Services.md
  18. 14
      docs/en/Entity-Framework-Core.md
  19. 4
      docs/en/Exception-Handling.md
  20. 16
      docs/en/MongoDB.md
  21. 3
      docs/en/Themes/Basic.md
  22. 28
      docs/en/Tutorials/Part-10.md
  23. 2
      docs/en/Tutorials/Part-5.md
  24. 2
      docs/en/Tutorials/Part-9.md
  25. 2
      docs/en/UI/Angular/Component-Replacement.md
  26. 89
      docs/en/UI/AspNetCore/Basic-Theme.md
  27. 45
      docs/en/UI/AspNetCore/Branding.md
  28. 3
      docs/en/UI/AspNetCore/Breadcrumbs.md
  29. 16
      docs/en/UI/AspNetCore/Customization-User-Interface.md
  30. 263
      docs/en/UI/AspNetCore/Data-Tables.md
  31. 92
      docs/en/UI/AspNetCore/Dynamic-JavaScript-Proxies.md
  32. 2
      docs/en/UI/AspNetCore/Layout-Hooks.md
  33. 3
      docs/en/UI/AspNetCore/Libraries/DatatablesNet.md
  34. 2
      docs/en/UI/AspNetCore/Navigation-Menu.md
  35. 159
      docs/en/UI/AspNetCore/Overall.md
  36. 58
      docs/en/UI/AspNetCore/Page-Header.md
  37. 4
      docs/en/UI/AspNetCore/Tag-Helpers/Index.md
  38. 2
      docs/en/UI/AspNetCore/Theming.md
  39. 75
      docs/en/UI/AspNetCore/Toolbars.md
  40. 2
      docs/en/UI/Blazor/Localization.md
  41. 3
      docs/en/UI/Blazor/Message.md
  42. 3
      docs/en/UI/Blazor/Notification.md
  43. 4
      docs/en/UI/Blazor/Overall.md
  44. 3
      docs/en/UI/Blazor/Services/Notification.md
  45. 2
      docs/en/UI/Blazor/Settings.md
  46. 50
      docs/en/docs-nav.json
  47. BIN
      docs/en/images/branding-appname.png
  48. BIN
      docs/en/images/branding-nobrand.png
  49. BIN
      docs/en/images/datatables-custom-render-date.png
  50. BIN
      docs/en/images/datatables-default-render-date.png
  51. BIN
      docs/en/images/datatables-example.png
  52. BIN
      docs/en/images/datatables-row-actions-confirmation.png
  53. BIN
      docs/en/images/datatables-row-actions-icon.png
  54. BIN
      docs/en/images/datatables-row-actions.png
  55. BIN
      docs/en/images/example-global-styles.png
  56. 4
      docs/zh-Hans/Application-Services.md
  57. 2
      docs/zh-Hans/Authorization.md
  58. 2
      docs/zh-Hans/Background-Workers.md
  59. 2
      docs/zh-Hans/Blog-Posts/2020-05-08 v2_7_Release/Post.md
  60. 36
      docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md
  61. 4
      docs/zh-Hans/Entity-Framework-Core-Migrations.md
  62. 6
      docs/zh-Hans/Entity-Framework-Core.md
  63. 354
      docs/zh-Hans/Getting-Started-AspNetCore-Application.md
  64. 2
      docs/zh-Hans/How-To/Customize-SignIn-Manager.md
  65. 10
      docs/zh-Hans/MongoDB.md
  66. 10
      docs/zh-Hans/Tutorials/Part-1.md
  67. 4
      docs/zh-Hans/UI/Angular/Component-Replacement.md
  68. 6
      docs/zh-Hans/UI/AspNetCore/Customization-User-Interface.md
  69. 131
      framework/.editorconfig
  70. 16
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LanguageSwitch.razor
  71. 3
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
  72. 29
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs
  73. 1
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor
  74. 4
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor
  75. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor.cs
  76. 1
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ExceptionHandling/UserExceptionInformer.cs
  77. 12
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/IUiNotificationService.cs
  78. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Messages/SimpleUiMessageService.cs
  79. 27
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/NullUiNotificationService.cs
  80. 22
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/AbpComponentBase.cs
  81. 0
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/IUiMessageService.cs
  82. 0
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageEventArgs.cs
  83. 0
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageOptions.cs
  84. 0
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageType.cs
  85. 13
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/IUiNotificationService.cs
  86. 28
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/NullUiNotificationService.cs
  87. 23
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationEventArgs.cs
  88. 20
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationOptions.cs
  89. 10
      framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationType.cs
  90. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs
  91. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs
  92. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
  93. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
  94. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
  95. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
  96. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
  97. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  98. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  99. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  100. 110
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs

1
.gitignore

@ -6,6 +6,7 @@
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

2
docs/en/API/Dynamic-CSharp-API-Clients.md

@ -1,4 +1,4 @@
# Dynamic C# API Clients
# Dynamic C# API Client Proxies
ABP can dynamically create C# API client proxies to call remote HTTP services (REST APIs). In this way, you don't need to deal with `HttpClient` and other low level HTTP features to call remote services and get results.

6
docs/en/Application-Services.md

@ -342,12 +342,12 @@ public class DistrictAppService
{
}
protected override async Task DeleteByIdAsync(DistrictKey id)
protected async override Task DeleteByIdAsync(DistrictKey id)
{
await Repository.DeleteAsync(d => d.CityId == id.CityId && d.Name == id.Name);
}
protected override async Task<District> GetEntityByIdAsync(DistrictKey id)
protected async override Task<District> GetEntityByIdAsync(DistrictKey id)
{
return await AsyncQueryableExecuter.FirstOrDefaultAsync(
Repository.Where(d => d.CityId == id.CityId && d.Name == id.Name)
@ -400,7 +400,7 @@ public class MyPeopleAppService : CrudAppService<Person, PersonDto, Guid>
{
}
protected override async Task CheckDeletePolicyAsync()
protected async override Task CheckDeletePolicyAsync()
{
await AuthorizationService.CheckAsync("...");
}

4
docs/en/Authorization.md

@ -234,7 +234,7 @@ context
When you write this code inside your permission definition provider, it finds the "role deletion" permission of the [Identity Module](Modules/Identity.md) and disabled the permission, so no one can delete a role on the application.
> Tip: It is better to check the value returned by the `GetPermissionOrNull` method since it may return null if the given permission was not defined.
> Tip: It is better to check the value returned by the `GetPermissionOrNull` method since it may return null if the given permission was not defined.
## IAuthorizationService
@ -354,7 +354,7 @@ public class SystemAdminPermissionValueProvider : PermissionValueProvider
public override string Name => "SystemAdmin";
public override async Task<PermissionGrantResult>
public async override Task<PermissionGrantResult>
CheckAsync(PermissionValueCheckContext context)
{
if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")

2
docs/en/Background-Workers-Quartz.md

@ -37,7 +37,7 @@ public class YourModule : AbpModule
````
> Quartz background worker integration provided `QuartzPeriodicBackgroundWorkerAdapter` to adapt `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived class. So, you can still fllow the [background workers document](Background-Workers.md) to define the background worker.
> `BackgroundJobWorker` checks todo jobs every 5 seconds, but quartz will not block when long time jobs are executing. So,after Added Quartz background worker integration, you also need to add [Quartz Background Jobs](Background-Jobs-Quartz.md) or [Hangfire Background Jobs](Background-Jobs-Hangfire.md) to avoid duplicate execution jobs.
> `BackgroundJobWorker` checks jobs every 5 seconds, but quartz will not block when long time jobs are executing. So,after Added Quartz background worker integration, you also need to add [Quartz Background Jobs](Background-Jobs-Quartz.md) or [Hangfire Background Jobs](Background-Jobs-Hangfire.md) to avoid duplicate execution jobs.
## Configuration

2
docs/en/Background-Workers.md

@ -54,7 +54,7 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
Timer.Period = 600000; //10 minutes
}
protected override async Task DoWorkAsync(
protected async override Task DoWorkAsync(
PeriodicBackgroundWorkerContext workerContext)
{
Logger.LogInformation("Starting: Setting status of inactive users...");

8
docs/en/Blog-Posts/2020-05-08 v2_7_Release/Post.md

@ -16,7 +16,7 @@ ABP.IO Platform is rapidly growing and we are getting more and more contribution
### Object Extending System
In the last few releases, we've mostly focused on providing ways to extend existing modules when you use them as NuGet/NPM Packages.
In the last few releases, we've mostly focused on providing ways to extend existing modules when you use them as NuGet/NPM Packages.
The Object Extending System allows module developers to create extensible modules and allows application developers to customize and extend a module easily.
@ -43,7 +43,7 @@ ObjectExtensionManager.Instance
options.Attributes.Add(new RequiredAttribute());
options.Attributes.Add(
new StringLengthAttribute(32) {
MinimumLength = 6
MinimumLength = 6
}
);
});
@ -121,7 +121,7 @@ Just create a class derived from the `ExceptionSubscriber` class in your applica
````csharp
public class MyExceptionSubscriber : ExceptionSubscriber
{
public override async Task HandleAsync(ExceptionNotificationContext context)
public async override Task HandleAsync(ExceptionNotificationContext context)
{
//TODO...
}
@ -244,4 +244,4 @@ We ([Volosoft](https://volosoft.com/) - the core team behind the ABP.IO platform
[ABP Framework](https://abp.io/) provides all the infrastructure and application independent framework features to make you more productive, focus on your own business code and implement software development best practices. It provides you a well defined and comfortable development experience without repeating yourself.
[ABP Commercial](https://commercial.abp.io/) provides pre-built functionalities, themes and tooling to save your time if your requirements involve these functionalities in addition to the premium support for the framework and the pre-built modules.
[ABP Commercial](https://commercial.abp.io/) provides pre-built functionalities, themes and tooling to save your time if your requirements involve these functionalities in addition to the premium support for the framework and the pre-built modules.

8
docs/en/Community-Articles/2020-04-19-Customize-the-SignIn-Manager/POST.md

@ -1,6 +1,6 @@
# How to Customize the SignIn Manager for ABP Applications
After creating a new application using the [application startup template](https://docs.abp.io/en/abp/latest/Startup-Templates/Application), you may want extend or change the default behavior of the SignIn Manager for your authentication and registration flow needs. ABP [Account Module](https://docs.abp.io/en/abp/latest/Modules/Account) uses the [Identity Management Module](https://docs.abp.io/en/abp/latest/Modules/Identity) for SignIn Manager and the [Identity Management Module](https://docs.abp.io/en/abp/latest/Modules/Identity) uses default [Microsoft Identity SignIn Manager](https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs) ([see here](https://github.com/abpframework/abp/blob/be32a55449e270d2d456df3dabdc91f3ffdd4fa9/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs#L17)).
After creating a new application using the [application startup template](https://docs.abp.io/en/abp/latest/Startup-Templates/Application), you may want extend or change the default behavior of the SignIn Manager for your authentication and registration flow needs. ABP [Account Module](https://docs.abp.io/en/abp/latest/Modules/Account) uses the [Identity Management Module](https://docs.abp.io/en/abp/latest/Modules/Identity) for SignIn Manager and the [Identity Management Module](https://docs.abp.io/en/abp/latest/Modules/Identity) uses default [Microsoft Identity SignIn Manager](https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs) ([see here](https://github.com/abpframework/abp/blob/be32a55449e270d2d456df3dabdc91f3ffdd4fa9/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs#L17)).
To write your Custom SignIn Manager, you need to extend [Microsoft Identity SignIn Manager](https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs) class and register it to the DI container.
@ -27,7 +27,7 @@ public class CustomSignInManager : Microsoft.AspNetCore.Identity.SignInManager<V
}
````
> It is important to use **Volo.Abp.Identity.IdentityUser** type for SignInManager to inherit, not the AppUser of your application.
> It is important to use **Volo.Abp.Identity.IdentityUser** type for SignInManager to inherit, not the AppUser of your application.
Afterwards you can override any of the SignIn Manager methods you need and add new methods and properties needed for your authentication or registration flow.
@ -38,7 +38,7 @@ In this case we'll be overriding the `GetExternalLoginInfoAsync` method which is
A good way to override a method is copying its [source code](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Identity/Core/src/SignInManager.cs#L638-L674). In this case, we will be using a minorly modified version of the source code which explicitly shows the namespaces of the methods and properties to help better understanding of the concept.
````csharp
public override async Task<Microsoft.AspNetCore.Identity.ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
public async override Task<Microsoft.AspNetCore.Identity.ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
{
var auth = await Context.AuthenticateAsync(Microsoft.AspNetCore.Identity.IdentityConstants.ExternalScheme);
var items = auth?.Properties?.Items;
@ -93,4 +93,4 @@ PreConfigure<IdentityBuilder>(identityBuilder =>
## The Source Code
You can find the source code of the completed example [here](https://github.com/abpframework/abp-samples/tree/master/Authentication-Customization).
You can find the source code of the completed example [here](https://github.com/abpframework/abp-samples/tree/master/Authentication-Customization).

14
docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md

@ -33,7 +33,7 @@ namespace PasswordlessAuthentication.Web
}
//We need to override this method as well.
public override async Task<string> GetUserModifierAsync(string purpose, UserManager<TUser> manager, TUser user)
public async override Task<string> GetUserModifierAsync(string purpose, UserManager<TUser> manager, TUser user)
{
var userId = await manager.GetUserIdAsync(user);
@ -105,7 +105,7 @@ namespace PasswordlessAuthentication.Web.Pages
UserManager = userManager;
_userRepository = userRepository;
}
public ActionResult OnGet()
{
if (!CurrentUser.IsAuthenticated)
@ -115,15 +115,15 @@ namespace PasswordlessAuthentication.Web.Pages
return Page();
}
//added for passwordless authentication
public async Task<IActionResult> OnPostGeneratePasswordlessTokenAsync()
{
var adminUser = await _userRepository.FindByNormalizedUserNameAsync("admin");
var token = await UserManager.GenerateUserTokenAsync(adminUser, "PasswordlessLoginProvider",
"passwordless-auth");
PasswordlessLoginUrl = Url.Action("Login", "Passwordless",
new {token = token, userId = adminUser.Id.ToString()}, Request.Scheme);
@ -238,7 +238,7 @@ namespace PasswordlessAuthentication.Web.Controllers
return Redirect("/");
}
private static IEnumerable<Claim> CreateClaims(IUser user, IEnumerable<string> roles)
{
var claims = new List<Claim>
@ -272,4 +272,4 @@ That's all! We created a passwordless login with 7 steps.
## Source Code
The completed sample is available on [GitHub repository](https://github.com/abpframework/abp-samples/tree/master/PasswordlessAuthentication).
The completed sample is available on [GitHub repository](https://github.com/abpframework/abp-samples/tree/master/PasswordlessAuthentication).

46
docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/POST.md

@ -0,0 +1,46 @@
# How to add a new language to your ABP project?
Adding a new language to your ABP project is pretty simple. Let's add the German language to our ABP project:
1. Go to your solution's root folder and write the following CLI command. This command will generate an empty translation file from English.
```bash
abp translate -c de-DE
```
Check out for [the complete supported culture codes](https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/supported-culture-codes).
(For internal development `D:\Github\abp` and `D:\Github\volo\abp`)
2. Fill the `target` fields in your target language.
![Fill target fields](language-target.png)
3. Copy `abp-translation.json` your solution's root folder (Do not change the filename!)
4. Run the following command. This command will create the necessary `json` files.
```bash
abp translate --apply
```
5. Open your solution and add the new language to the language list. To do this;
* open `MyProjectNameDomainModule.cs` and in `ConfigureServices` you'll find `Configure<AbpLocalizationOptions>`. If you have `HttpApi.Host` project then you need to add this in `MyProjectNameHttpApiHostModule.cs`
```
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsche", "de"));
```
![Add to languages](add-to-languages.png)
The last parameter is the flag icon. You can find the list of flag icons on https://flagicons.lipis.dev/
6. The last step is running the DbMigrator project. It will seed the database for the new language.
![The database table](database-table.png)
Close the IIS Express / Kestrel to invalidate the language cache and run the project. You will see the new language on your website.
![See the final result](website-new-language.png)

BIN
docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/add-to-languages.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/database-table.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/language-target.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
docs/en/Community-Articles/2020-11-02-How-To-Add-New-Language/website-new-language.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

42
docs/en/Customizing-Application-Modules-Overriding-Services.md

@ -29,7 +29,7 @@ public class TestAppService : IIdentityUserAppService, ITransientDependency
}
````
The dependency injection system allows to register multiple services for the same interface. The last registered one is used when the interface is injected. It is a good practice to explicitly replace the service.
The dependency injection system allows to register multiple services for the same interface. The last registered one is used when the interface is injected. It is a good practice to explicitly replace the service.
Example:
@ -76,7 +76,7 @@ public class MyIdentityUserAppService : IdentityUserAppService
{
}
public override async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
public async override Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
{
if (input.PhoneNumber.IsNullOrWhiteSpace())
{
@ -109,33 +109,33 @@ public class MyIdentityUserManager : IdentityUserManager
{
public MyIdentityUserManager(
IdentityUserStore store,
IIdentityRoleRepository roleRepository,
IIdentityRoleRepository roleRepository,
IIdentityUserRepository userRepository,
IOptions<IdentityOptions> optionsAccessor,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<IdentityUser> passwordHasher,
IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<IdentityUserManager> logger,
ICancellationTokenProvider cancellationTokenProvider) :
ILogger<IdentityUserManager> logger,
ICancellationTokenProvider cancellationTokenProvider) :
base(store,
roleRepository,
userRepository,
optionsAccessor,
passwordHasher,
userValidators,
userRepository,
optionsAccessor,
passwordHasher,
userValidators,
passwordValidators,
keyNormalizer,
errors,
services,
logger,
keyNormalizer,
errors,
services,
logger,
cancellationTokenProvider)
{
}
public override async Task<IdentityResult> CreateAsync(IdentityUser user)
public async override Task<IdentityResult> CreateAsync(IdentityUser user)
{
if (user.PhoneNumber.IsNullOrWhiteSpace())
{
@ -182,7 +182,7 @@ namespace MyProject.Controllers
}
public override async Task SendPasswordResetCodeAsync(
public async override Task SendPasswordResetCodeAsync(
SendPasswordResetCodeDto input)
{
Logger.LogInformation("Your custom logic...");
@ -214,7 +214,7 @@ Assuming that you've already added a `SocialSecurityNumber` as described in the
You can use the [object extension system](Object-Extensions.md) to add the property to the `IdentityUserDto`. Write this code inside the `YourProjectNameDtoExtensions` class comes with the application startup template:
````csharp
ObjectExtensionManager.Instance
ObjectExtensionManager.Instance
.AddOrUpdateProperty<IdentityUserDto, string>(
"SocialSecurityNumber"
);
@ -286,8 +286,8 @@ ObjectExtensionManager.Instance
.AddOrUpdateProperty<string>(
new[]
{
typeof(IdentityUserDto),
typeof(IdentityUserCreateDto),
typeof(IdentityUserDto),
typeof(IdentityUserCreateDto),
typeof(IdentityUserUpdateDto)
},
"SocialSecurityNumber"

6
docs/en/Domain-Driven-Design.md

@ -19,8 +19,12 @@ ABP follows DDD principles and patterns to achieve a layered application model w
- **Domain Layer**: Includes business objects and the core (domain) business rules. This is the heart of the application.
- **Infrastructure Layer**: Provides generic technical capabilities that support higher layers mostly using 3rd-party libraries.
DDD mostly interest in the **Domain** and the **Application** layers, rather than the Infrastructure and the Presentation layers.
## Contents
See the following documents to learn what ABP Framework provides to you to implement DDD in your project.
* **Domain Layer**
* [Entities & Aggregate Roots](Entities.md)
* Value Objects
@ -30,4 +34,4 @@ ABP follows DDD principles and patterns to achieve a layered application model w
* **Application Layer**
* [Application Services](Application-Services.md)
* [Data Transfer Objects (DTOs)](Data-Transfer-Objects.md)
* Unit of Work
* [Unit of Work](Unit-Of-Work.md)

4
docs/en/Domain-Services.md

@ -1,3 +1,3 @@
# ABP Documentation
# Domain Services
TODO!
TODO

14
docs/en/Entity-Framework-Core.md

@ -92,7 +92,7 @@ protected override void OnModelCreating(ModelBuilder builder)
b.ToTable("Books");
//Configure the base properties
b.ConfigureByConvention();
b.ConfigureByConvention();
//Configure other properties (if you are using the fluent API)
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
@ -113,7 +113,7 @@ If you have multiple databases in your application, you can configure the connec
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpDbContext<MyDbContext>
{
}
```
@ -254,7 +254,7 @@ If you want to replace default repository implementation with your custom reposi
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.AddDefaultRepositories();
//Replaces IRepository<Book, Guid>
options.AddRepository<Book, BookRepository>();
});
@ -263,7 +263,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete a specific entity in a more efficient way:
````csharp
public override async Task DeleteAsync(
public async override Task DeleteAsync(
Guid id,
bool autoSave = false,
CancellationToken cancellationToken = default)
@ -365,7 +365,7 @@ public class MyRepositoryBase<TEntity>
: EfCoreRepository<BookStoreDbContext, TEntity>
where TEntity : class, IEntity
{
public MyRepositoryBase(IDbContextProvider<BookStoreDbContext> dbContextProvider)
public MyRepositoryBase(IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
@ -395,7 +395,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
typeof(MyRepositoryBase<,>),
typeof(MyRepositoryBase<>)
);
//...
});
```
@ -448,4 +448,4 @@ In this example, `OtherDbContext` implements `IBookStoreDbContext`. This feature
## See Also
* [Entities](Entities.md)
* [Entities](Entities.md)

4
docs/en/Exception-Handling.md

@ -85,7 +85,7 @@ Error **details** in an optional field of the JSON error message. Thrown `Except
### Logging
Caught exceptions are automatically logged.
Caught exceptions are automatically logged.
#### Log Level
@ -300,7 +300,7 @@ In this case, create a class derived from the `ExceptionSubscriber` class in you
````csharp
public class MyExceptionSubscriber : ExceptionSubscriber
{
public override async Task HandleAsync(ExceptionNotificationContext context)
public async override Task HandleAsync(ExceptionNotificationContext context)
{
//TODO...
}

16
docs/en/MongoDB.md

@ -40,7 +40,7 @@ public class MyDbContext : AbpMongoDbContext
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
//Customize the configuration for your collections.
}
}
@ -62,7 +62,7 @@ So, most of times you don't need to explicitly configure registration for your e
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.Entity<Question>(b =>
{
b.CollectionName = "MyQuestions"; //Sets the collection name
@ -88,7 +88,7 @@ If you have multiple databases in your application, you can configure the connec
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpMongoDbContext
{
}
````
@ -202,7 +202,7 @@ You generally want to derive from the `IRepository` to inherit standard reposito
Example implementation of the `IBookRepository` interface:
```csharp
public class BookRepository :
public class BookRepository :
MongoDbRepository<BookStoreMongoDbContext, Book, Guid>,
IBookRepository
{
@ -242,9 +242,9 @@ context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete an entity in a more efficient way:
```csharp
public override async Task DeleteAsync(
Guid id,
bool autoSave = false,
public async override Task DeleteAsync(
Guid id,
bool autoSave = false,
CancellationToken cancellationToken = default)
{
//TODO: Custom implementation of the delete method
@ -381,4 +381,4 @@ context.Services.AddMongoDbContext<OtherMongoDbContext>(options =>
});
```
In this example, `OtherMongoDbContext` implements `IBookStoreMongoDbContext`. This feature allows you to have multiple MongoDbContext (one per module) on development, but single MongoDbContext (implements all interfaces of all MongoDbContexts) on runtime.
In this example, `OtherMongoDbContext` implements `IBookStoreMongoDbContext`. This feature allows you to have multiple MongoDbContext (one per module) on development, but single MongoDbContext (implements all interfaces of all MongoDbContexts) on runtime.

3
docs/en/Themes/Basic.md

@ -1,3 +1,2 @@
## Basic Theme
This document has been moved to [here](../UI/AspNetCore/Basic-Theme.md).
TODO

28
docs/en/Tutorials/Part-10.md

@ -10,7 +10,7 @@
In this tutorial series, you will build an ABP based web application named `Acme.BookStore`. This application is used to manage a list of books and their authors. It is developed using the following technologies:
* **{{DB_Value}}** as the ORM provider.
* **{{DB_Value}}** as the ORM provider.
* **{{UI_Value}}** as the UI Framework.
This tutorial is organized as the following parts;
@ -78,7 +78,7 @@ builder.Entity<Book>(b =>
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
// ADD THE MAPPING FOR THE RELATION
b.HasOne<Author>().WithMany().HasForeignKey(x => x.AuthorId).IsRequired();
});
@ -362,7 +362,7 @@ namespace Acme.BookStore.Books
DeletePolicyName = BookStorePermissions.Books.Create;
}
public override async Task<BookDto> GetAsync(Guid id)
public async override Task<BookDto> GetAsync(Guid id)
{
await CheckGetPolicyAsync();
@ -384,7 +384,7 @@ namespace Acme.BookStore.Books
return bookDto;
}
public override async Task<PagedResultDto<BookDto>>
public async override Task<PagedResultDto<BookDto>>
GetListAsync(PagedAndSortedResultRequestDto input)
{
await CheckGetListPolicyAsync();
@ -485,7 +485,7 @@ namespace Acme.BookStore.Books
DeletePolicyName = BookStorePermissions.Books.Create;
}
public override async Task<BookDto> GetAsync(Guid id)
public async override Task<BookDto> GetAsync(Guid id)
{
await CheckGetPolicyAsync();
@ -498,7 +498,7 @@ namespace Acme.BookStore.Books
return bookDto;
}
public override async Task<PagedResultDto<BookDto>>
public async override Task<PagedResultDto<BookDto>>
GetListAsync(PagedAndSortedResultRequestDto input)
{
await CheckGetListPolicyAsync();
@ -524,7 +524,7 @@ namespace Acme.BookStore.Books
var authorDictionary = await GetAuthorDictionaryAsync(books);
//Set AuthorName for the DTOs
bookDtos.ForEach(bookDto => bookDto.AuthorName =
bookDtos.ForEach(bookDto => bookDto.AuthorName =
authorDictionary[bookDto.AuthorId].Name);
//Get the total count with another query (required for the paging)
@ -622,7 +622,7 @@ namespace Acme.BookStore.Books
result.Items.ShouldContain(b => b.Name == "1984" &&
b.AuthorName == "George Orwell");
}
[Fact]
public async Task Should_Create_A_Valid_Book()
{
@ -645,7 +645,7 @@ namespace Acme.BookStore.Books
result.Id.ShouldNotBe(Guid.Empty);
result.Name.ShouldBe("New test book 42");
}
[Fact]
public async Task Should_Not_Create_A_Book_Without_Name()
{
@ -1100,15 +1100,15 @@ The final `@code` block should be the following:
//ADDED A NEW FIELD
IReadOnlyList<AuthorLookupDto> authorList = Array.Empty<AuthorLookupDto>();
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();
canCreateBook = await
canCreateBook = await
AuthorizationService.IsGrantedAsync(BookStorePermissions.Books.Create);
canEditBook = await
canEditBook = await
AuthorizationService.IsGrantedAsync(BookStorePermissions.Books.Edit);
canDeleteBook = await
canDeleteBook = await
AuthorizationService.IsGrantedAsync(BookStorePermissions.Books.Delete);
//GET AUTHORS
@ -1164,4 +1164,4 @@ Add the following `Field` definition into the `ModalBody` of the *Edit* modal, a
That's all. We are reusing the `authorList` defined for the *Create* modal.
{{end}}
{{end}}

2
docs/en/Tutorials/Part-5.md

@ -487,7 +487,7 @@ Add the following code block to the end of the `Books.razor` file:
bool canEditBook;
bool canDeleteBook;
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();

2
docs/en/Tutorials/Part-9.md

@ -1038,7 +1038,7 @@ namespace Acme.BookStore.Blazor.Pages
EditingAuthor = new UpdateAuthorDto();
}
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
await SetPermissionsAsync();
await GetAuthorsAsync();

2
docs/en/UI/Angular/Component-Replacement.md

@ -45,7 +45,7 @@ Run the following command to generate a layout in `angular` folder:
yarn ng generate component my-application-layout
```
Add the following code in your layout template (`my-layout.component.html`) where you want the page to be loaded.
Add the following code in your layout template (`my-application-layout.component.html`) where you want the page to be loaded.
```html
<router-outlet></router-outlet>

89
docs/en/UI/AspNetCore/Basic-Theme.md

@ -1,3 +1,90 @@
# ASP.NET Core MVC / Razor Pages: The Basic Theme
This document is in progress. See the [Theming](Theming.md) document.
The Basic Theme is a theme implementation for the ASP.NET Core MVC / Razor Pages UI. It is a minimalist theme that doesn't add any styling on top of the plain [Bootstrap](https://getbootstrap.com/). You can take the Basic Theme as the **base theme** and build your own theme or styling on top of it. See the *Customization* section.
The Basic Theme has RTL (Right-to-Left language) support.
> If you are looking for a professional, enterprise ready theme, you can check the [Lepton Theme](https://commercial.abp.io/themes), which is a part of the [ABP Commercial](https://commercial.abp.io/).
> See the [Theming document](Theming.md) to learn about themes.
## Installation
**This theme is already installed** when you create a new solution using the [startup templates](../../Startup-Templates/Index.md). If you need to manually install it, follow the steps below:
* Install the [Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) NuGet package to your web project.
* Add `AbpAspNetCoreMvcUiBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the web project.
* Install the [@abp/aspnetcore.mvc.ui.theme.basic](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.basic) NPM package to your web project (e.g. `npm install @abp/aspnetcore.mvc.ui.theme.basic` or `yarn add @abp/aspnetcore.mvc.ui.theme.basic`).
* Run `gulp` command in a command line terminal in the web project's folder.
## Layouts
The Basic Theme implements the standard layouts. All the layouts implement the following parts;
* Global [Bundles](Bundling-Minification.md)
* [Page Alerts](Page-Alerts.md)
* [Layout Hooks](Layout-Hooks.md)
* [Widget](Widgets.md) Resources
### The Application Layout
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
Application Layout implements the following parts, in addition to the common parts mentioned above;
* Branding
* Main [Menu](Navigation-Menu.md)
* Main [Toolbar](Toolbars.md) with Language Selection & User Menu
### The Account Layout
![basic-theme-account-layout](../../images/basic-theme-account-layout.png)
Application Layout implements the following parts, in addition to the common parts mentioned above;
* Branding
* Main [Menu](Navigation-Menu.md)
* Main [Toolbar](Toolbars.md) with Language Selection & User Menu
* Tenant Switch Area
### Empty Layout
Empty layout is empty, as its name stands for. However, it implements the common parts mentioned above.
## Customization
You have two options two customize this theme:
### Overriding Styles/Components
In this approach, you continue to use the the theme as NuGet and NPM packages and customize the parts you need to. There are several ways to customize it;
#### Override the Styles
1. Create a CSS file in the `wwwroot` folder of your project:
![example-global-styles](../../images/example-global-styles.png)
2. Add the style file to the global bundle, in the `ConfigureServices` method of your [module](../../Module-Development-Basics.md):
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(BasicThemeBundles.Styles.Global, bundle =>
{
bundle.AddFiles("/styles/global-styles.css");
});
});
````
#### Override the Components
See the [User Interface Customization Guide](Customization-User-Interface.md) to learn how you can replace components, customize and extend the user interface.
### Copy & Customize
You can download the [source code](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) of the Basic Theme, copy the project content into your solution, re-arrange the package/module dependencies (see the Installation section above to understand how it was installed to the project) and freely customize the theme based on your application requirements.
## See Also
* [Theming](Theming.md)

45
docs/en/UI/AspNetCore/Branding.md

@ -0,0 +1,45 @@
# ASP.NET Core MVC / Razor Pages: Branding
## IBrandingProvider
`IBrandingProvider` is a simple interface that is used to show the application name and logo on the layout.
The screenshot below shows *MyProject* as the application name:
![branding-nobrand](../../images/branding-nobrand.png)
You can implement the `IBrandingProvider` interface or inherit from the `DefaultBrandingProvider` to set the application name:
````csharp
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components;
using Volo.Abp.DependencyInjection;
namespace MyProject.Web
{
[Dependency(ReplaceServices = true)]
public class MyProjectBrandingProvider : DefaultBrandingProvider
{
public override string AppName => "Book Store";
}
}
````
The result will be like shown below:
![branding-appname](../../images/branding-appname.png)
`IBrandingProvider` has the following properties:
* `AppName`: The application name.
* `LogoUrl`: A URL to show the application logo.
* `LogoReverseUrl`: A URL to show the application logo on a reverse color theme (dark, for example).
> **Tip**: `IBrandingProvider` is used in every page refresh. For a multi-tenant application, you can return a tenant specific application name to customize it per tenant.
## Overriding the Branding Area
The [Basic Theme](Basic-Theme.md) doesn't implement the logos. However, you can see the [UI Customization Guide](Customization-User-Interface.md) to learn how you can replace the branding area with a custom view component.
An example screenshot with an image is used in the branding area:
![bookstore-added-logo](../../images/bookstore-added-logo.png)

3
docs/en/UI/AspNetCore/Breadcrumbs.md

@ -1,3 +0,0 @@
# Toolbars
TODO

16
docs/en/UI/AspNetCore/Customization-User-Interface.md

@ -28,15 +28,15 @@ namespace Acme.BookStore.Web.Pages.Identity.Users
public class MyEditModalModel : EditModalModel
{
public MyEditModalModel(
IIdentityUserAppService identityUserAppService,
IIdentityUserAppService identityUserAppService,
IIdentityRoleAppService identityRoleAppService
) : base(
identityUserAppService,
identityUserAppService,
identityRoleAppService)
{
}
public override async Task<IActionResult> OnPostAsync()
public async override Task<IActionResult> OnPostAsync()
{
//TODO: Additional logic
await base.OnPostAsync();
@ -84,10 +84,10 @@ Create a page model class deriving from the ` LoginModel ` (defined in the ` Vol
public class MyLoginModel : LoginModel
{
public MyLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions
) : base(
schemeProvider,
schemeProvider,
accountOptions)
{
@ -128,11 +128,11 @@ The ABP Framework, pre-built themes and modules define some **re-usable view com
### Example
The screenshot below was taken from the **basic theme** comes with the application startup template.
The screenshot below was taken from the [Basic Theme](Basic-Theme.md) comes with the application startup template.
![bookstore-brand-area-highlighted](../../images/bookstore-brand-area-highlighted.png)
[The basic theme](../../Themes/Basic.md) defines some view components for the layout. For example, the highlighted area with the red rectangle above is called **Brand component**. You probably want to customize this component by adding your **own application logo**. Let's see how to do it.
The [Basic Theme](Basic-Theme.md) defines some view components for the layout. For example, the highlighted area with the red rectangle above is called **Brand component**. You probably want to customize this component by adding your **own application logo**. Let's see how to do it.
First, create your logo and place under a folder in your web application. We used `wwwroot/logos/bookstore-logo.png` path. Then copy the Brand component's view ([from here](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml)) from the basic theme files under the `Themes/Basic/Components/Brand` folder. The result should be similar the picture below:
@ -437,7 +437,7 @@ See the layouts section below to learn more about the layout system.
Layout system allows themes to define standard, named layouts and allows any page to select a proper layout for its purpose. There are three pre-defined layouts:
* "**Application**": The main (and the default) layout for an application. It typically contains header, menu (sidebar), footer, toolbar... etc.
* "**Application**": The main (and the default) layout for an application. It typically contains header, menu (sidebar), footer, toolbar... etc.
* "**Account**": This layout is used by login, register and other similar pages. It is used for the pages under the `/Pages/Account` folder by default.
* "**Empty**": Empty and minimal layout.

263
docs/en/UI/AspNetCore/Data-Tables.md

@ -0,0 +1,263 @@
# ASP.NET Core MVC / Razor Pages: Data Tables
A Data Table (aka Data Grid) is a UI component to show tabular data to the users. There are a lot of Data table components/libraries and **you can use any one you like** with the ABP Framework. However, the startup templates come with the [DataTables.Net](https://datatables.net/) library as **pre-installed and configured**. ABP Framework provides adapters for this library and make it easy to use with the API endpoints.
An example screenshot from the user management page that shows the user list in a data table:
![datatables-example](../../images/datatables-example.png)
## DataTables.Net Integration
First of all, you can follow the official documentation to understand how the [DataTables.Net](https://datatables.net/) works. This section will focus on the ABP addons & integration points rather than fully covering the usage of this library.
### A Quick Example
You can follow the [web application development tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC) for a complete example application that uses the DataTables.Net as the Data Table. This section shows a minimalist example.
You do nothing to add DataTables.Net library to the page since it is already added to the global [bundle](Bundling-Minification.md) by default.
First, add an `abp-table` as shown below, with an `id`:
````html
<abp-table striped-rows="true" id="BooksTable"></abp-table>
````
> `abp-table` is a [Tag Helper](Tag-Helpers/Index.md) defined by the ABP Framework, but a simple `<table...>` tag would also work.
Then call the `DataTable` plugin on the table selector:
````js
var dataTable = $('#BooksTable').DataTable(
abp.libs.datatables.normalizeConfiguration({
serverSide: true,
paging: true,
order: [[1, "asc"]],
searching: false,
ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),
columnDefs: [
{
title: l('Actions'),
rowAction: {
items:
[
{
text: l('Edit'),
action: function (data) {
///...
}
}
]
}
},
{
title: l('Name'),
data: "name"
},
{
title: l('PublishDate'),
data: "publishDate",
render: function (data) {
return luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
}).toLocaleString();
}
},
{
title: l('Price'),
data: "price"
}
]
})
);
````
The example code above uses some ABP integration features those will be explained in the next sections.
### Configuration Normalization
`abp.libs.datatables.normalizeConfiguration` function takes a DataTables configuration and normalizes to simplify it;
* Sets `scrollX` option to `true`, if not set.
* Sets `target` index for the column definitions.
* Sets the `language` option to [localize](../../Localization.md) the table in the current language.
#### Default Configuration
`normalizeConfiguration` uses the default configuration. You can change the default configuration using the `abp.libs.datatables.defaultConfigurations` object. Example:
````js
abp.libs.datatables.defaultConfigurations.scrollX = false;
````
Here, the all configuration options;
* `scrollX`: `false` by default.
* `dom`: Default value is `<"dataTable_filters"f>rt<"row dataTable_footer"<"col-auto"l><"col-auto"i><"col"p>>`.
* `language`: A function that returns the localization text using the current language.
### AJAX Adapter
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.
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.
### Row Actions
`rowAction` is an option defined by the ABP Framework to the column definitions to show a drop down button to take actions for a row in the table.
The example screenshot below shows the actions for each user in the user management table:
![datatables-example](../../images/datatables-row-actions.png)
`rowAction` is defined as a part of a column definition:
````csharp
{
title: l('Actions'),
rowAction: {
//TODO: CONFIGURATION
}
},
````
**Example: Show *Edit* and *Delete* actions for a book row**
````js
{
title: l('Actions'),
rowAction: {
items:
[
{
text: l('Edit'),
action: function (data) {
//TODO: Open a modal to edit the book
}
},
{
text: l('Delete'),
confirmMessage: function (data) {
return "Are you sure to delete the book " + data.record.name;
},
action: function (data) {
acme.bookStore.books.book
.delete(data.record.id)
.then(function() {
abp.notify.info("Successfully deleted!");
data.table.ajax.reload();
});
}
}
]
}
},
````
#### Action Items
`items` is an array of action definitions. An action definition can have the following options;
* `text`: The text (a `string`) for this action to be shown in the actions drop down.
* `action`: A `function` that is executed when the user clicks to the action. The function takes a `data` argument that has the following fields;
* `data.record`: This is the data object related to the row. You can access the data fields like `data.record.id`, `data.record.name`... etc.
* `data.table`: The DataTables instance.
* `confirmMessage`: A `function` (see the example above) that returns a message (`string`) to show a dialog to get a confirmation from the user before executing the `action`. Example confirmation dialog:
![datatables-row-actions-confirmation](../../images/datatables-row-actions-confirmation.png)
You can use the [localization](JavaScript-API/Localization.md) system to show a localized message.
* `visible`: A `bool` or a `function` that returns a `bool`. If the result is `false`, then the action is not shown in the actions dropdown. This is generally combined by the [authorization](JavaScript-API/Auth.md) system to hide the action if the user has no permission to take this action. Example:
````js
visible: abp.auth.isGranted('BookStore.Books.Delete');
````
If you define a `function`, then the `function` has two arguments: `record` (the data object of the related row) and the `table` (the DataTable instance). So, you can decide to show/hide the action dynamically, based on the row data and other conditions.
* `iconClass`: Can be used to show a font-icon, like a [Font-Awesome](https://fontawesome.com/) icon (ex: `fas fa-trash-alt`), near to the action text. Example screenshot:
![datatables-row-actions-confirmation](../../images/datatables-row-actions-icon.png)
* `enabled`: A `function` that returns a `bool` to disable the action. The `function` takes a `data` object with two fields: `data.record` is the data object related to the row and `data.table` is the DataTables instance.
* `displayNameHtml`: Set this to `true` is the `text` value contains HTML tags.
There are some rules with the action items;
* If none of the action items is visible then the actions column is not rendered.
### Data Format
#### The Problem
See the *Creation Time* column in the example below:
````js
{
title: l('CreationTime'),
data: "creationTime",
render: function (data) {
return luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
}).toLocaleString(luxon.DateTime.DATETIME_SHORT);
}
}
````
The `render` is a standard DataTables option to render the column content by a custom function. This example uses the [luxon](https://moment.github.io/luxon/) library (which is installed by default) to write a human readable value of the `creationTime` in the current user's language. Example output of the column:
![datatables-custom-render-date](../../images/datatables-custom-render-date.png)
If you don't define the render option, then the result will be ugly and not user friendly:
![datatables-custom-render-date](../../images/datatables-default-render-date.png)
However, rendering a `DateTime` is almost same and repeating the same rendering logic everywhere is against to the DRY (Don't Repeat Yourself!) principle.
#### dataFormat Option
`dataFormat` column option specifies the data format that is used to render the column data. The same output could be accomplished using the following column definition:
````js
{
title: l('CreationTime'),
data: "creationTime",
dataFormat: 'datetime'
}
````
`dataFormat: 'datetime'` specifies the data format for this column. There are a few pre-defined `dataFormat`s:
* `boolean`: Shows a `check` icon for `true` and `times` icon for `false` value and useful to render `bool` values.
* `date`: Shows date part of a `DateTime` value, formatted based on the current culture.
* `datetime`: Shows date & time (excluding seconds) of a `DateTime` value, formatted based on the current culture.
### Default Renderers
`abp.libs.datatables.defaultRenderers` option allows you to define new data formats and set renderers for them.
**Example: Render male / female icons based on the gender**
````js
abp.libs.datatables.defaultRenderers['gender'] = function(value) {
if (value === 'f') {
return '<i class="fa fa-venus"></i>';
} else {
return '<i class="fa fa-mars"></i>';
}
};
````
Assuming that the possible values for a column data is `f` and `m`, the `gender` data format shows female/male icons instead of `f` and `m` texts. You can now set `dataFormat: 'gender'` for a column definition that has the proper data values.
> You can write the default renderers in a single JavaScript file and add it to the [Global Script Bundle](Bundling-Minification.md), so you can reuse them in all the pages.
## Other Data Grids
You can use any library you like. For example, [see this article](https://community.abp.io/articles/using-devextreme-components-with-the-abp-framework-zb8z7yqv) to learn how to use DevExtreme Data Grid in your applications.

92
docs/en/UI/AspNetCore/Dynamic-JavaScript-Proxies.md

@ -1,3 +1,91 @@
# Dynamic JavaScript HTTP API Proxies
# Dynamic JavaScript API Client Proxies
TODO
It is typical to consume your HTTP APIs from your JavaScript code. To do that, you normally deal with low level AJAX calls, like $.ajax, or better [abp.ajax](JavaScript-API/Ajax.md). ABP Framework provides **a better way** to call your HTTP APIs from your JavaScript code: Dynamic JavaScript API Client Proxies!
## A Quick Example
Assume that you have an application service defined as shown below:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Authors
{
public interface IAuthorAppService : IApplicationService
{
Task<AuthorDto> GetAsync(Guid id);
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input);
Task<AuthorDto> CreateAsync(CreateAuthorDto input);
Task UpdateAsync(Guid id, UpdateAuthorDto input);
Task DeleteAsync(Guid id);
}
}
````
> You can follow the [web application development tutorial](../../Tutorials/Part-1.md) to learn how to create [application services](../../Application-Services.md), expose them as [HTTP APIs](../../API/Auto-API-Controllers.md) and consume from the JavaScript code as a complete example.
You can call any of the methods just like calling a JavaScript function. The JavaScript function has the identical function **name**, **parameters** and the **return value** with the C# method.
**Example: Get the authors list**
````js
acme.bookStore.authors.author.getList({
maxResultCount: 10
}).then(function(result){
console.log(result.items);
});
````
**Example: Delete an author**
```js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0') //Get id from somewhere!
.then(function() {
abp.notify.info('Successfully deleted!');
});
```
## AJAX Details
Dynamic JavaScript client proxy functions use the [abp.ajax](JavaScript-API/Ajax.md) under the hood. So, you have the same benefits like **automatic error handling**. Also, you can fully control the AJAX call by providing the options.
### The Return Value
Every function returns a [Deferred object](https://api.jquery.com/category/deferred-object/). That means you can chain with `then` to get the result, `catch` to handle the error, `always` to perform an action once the operation completes (success or failed).
### AJAX Options
Every function gets an additional **last parameter** after your own parameters. The last parameter is called as `ajaxParams`. It is an object that overrides the AJAX options.
**Example: Set `type` and `dataType` AJAX options**
````js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0', {
type: 'POST',
dataType: 'xml'
})
.then(function() {
abp.notify.info('Successfully deleted!');
});
````
See the [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) documentation for all the available options.
## Service Proxy Script Endpoint
The magic is done by the `/Abp/ServiceProxyScript` endpoint defined by the ABP Framework and automatically added to the layout. You can visit this endpoint in your application to see the client proxy function definitions. This script file is automatically generated by the ABP Framework based on the server side method definitions and the related HTTP endpoint details.
## See Also
* [Web Application Development Tutorial](../../Tutorials/Part-1.md)
* [Auto API Controllers](../../API/Auto-API-Controllers.md)
* [Dynamic C# API Client Proxies](../../API/Dynamic-CSharp-API-Clients.md)

2
docs/en/UI/AspNetCore/Layout-Hooks.md

@ -1,4 +1,4 @@
# ASP.NET Core MVC / Razor Pages Layout Hooks
# ASP.NET Core MVC / Razor Pages: Layout Hooks
ABP Framework theming system places the page layout into the [theme](Theming.md) NuGet packages. That means the final application doesn't include a `Layout.cshtml`, so you can't directly change the layout code to customize it.

3
docs/en/UI/AspNetCore/Libraries/DatatablesNet.md

@ -1,3 +0,0 @@
# ABP Datatables.Net Integration for ASP.NET Core UI
TODO

2
docs/en/UI/AspNetCore/Navigation-Menu.md

@ -83,7 +83,7 @@ Here, a few notes on the menu contributors;
There are more options of a menu item (the constructor of the `ApplicationMenuItem` class). Here, the list of all available options;
* `name` (`string`, required): The unique name of the menu item.
* `name` (`string`, required): The **unique name** of the menu item.
* `displayName` (`string`, required): Display name/text of the menu item. You can [localize](../../Localization.md) this as shown before.
* `url` (`string`): The URL of the menu item.
* `icon` (`string`): An icon name. Free [Font Awesome](https://fontawesome.com/) icon classes are supported out of the box. Example: `fa fa-book`. You can use any CSS font icon class as long as you include the necessary CSS files to your application.

159
docs/en/UI/AspNetCore/Overall.md

@ -0,0 +1,159 @@
# ASP.NET Core MVC / Razor Pages UI
## Introduction
ABP Framework provides a convenient and comfortable way of creating web applications using the ASP.NET Core MVC / Razor Pages as the User Interface framework.
> ABP doesn't offer a new/custom way of UI development. You can continue to use your current skills to create the UI. However, it offers a lot of features to make your development easier and have a more maintainable code base.
### MVC vs Razor Pages
ASP.NET Core provides two models for UI development:
* **[MVC (Model-View-Controller)](https://docs.microsoft.com/en-us/aspnet/core/mvc/)** is the classic way that exists from the version 1.0. This model can be used to create UI pages/components and HTTP APIs.
* **[Razor Pages](https://docs.microsoft.com/en-us/aspnet/core/razor-pages/)** was introduced with the ASP.NET Core 2.0 as a new way to create web pages.
**ABP Framework supports both** of the MVC and the Razor Pages models. However, it is suggested to create the **UI pages with Razor Pages** approach and use the **MVC model to build HTTP APIs**. So, all the pre-build modules, samples and the documentation is based on the Razor Pages for the UI development, while you can always apply the MVC pattern to create your own pages.
### Modularity
[Modularity](../../Module-Development-Basics.md) is one of the key goals of the ABP Framework. It is not different for the UI; It is possible to develop modular applications and reusable application modules with isolated and reusable UI pages and components.
The [application startup template](../../Startup-Templates/Application.md) comes with some application modules pre-installed. These modules have their own UI pages embedded into their own NuGet packages. You don't see their code in your solution, but they work as expected on runtime.
## Theme System
ABP Framework provides a complete [Theming](Theming.md) system with the following goals:
* Reusable [application modules](../../Modules/Index.md) are developed **theme-independent**, so they can work with any UI theme.
* UI theme is **decided by the final application**.
* The theme is distributed via NuGet/NPM packages, so it is **easily upgradable**.
* The final application can **customize** the selected theme.
### Current Themes
Currently, two themes are **officially provided**:
* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**.
* The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license.
There are also some community-driven themes for the ABP Framework (you can search on the web).
### Base Libraries
There are a set of standard JavaScript/CSS libraries that comes pre-installed and supported by all the themes:
- [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework.
- [JQuery](https://jquery.com/) for DOM manipulation.
- [DataTables.Net](https://datatables.net/) for data grids.
- [JQuery Validation](https://jqueryvalidation.org/) for client side & [unobtrusive](https://github.com/aspnet/jquery-validation-unobtrusive) validation
- [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library.
- [SweetAlert](https://sweetalert.js.org/) to show fancy alert message and confirmation dialogs.
- [Toastr](https://github.com/CodeSeven/toastr) to show toast notifications.
- [Lodesh](https://lodash.com/) as a utility library.
- [Luxon](https://moment.github.io/luxon/) for date/time operations.
- [JQuery Form](https://github.com/jquery-form/form) for AJAX forms.
- [bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) to show date pickers.
- [Select2](https://select2.org/) for better select/combo boxes.
- [Timeago](http://timeago.yarp.com/) to show automatically updating fuzzy timestamps.
- [malihu-custom-scrollbar-plugin](https://github.com/malihu/malihu-custom-scrollbar-plugin) for custom scrollbars.
You can use these libraries directly in your applications, without needing to manually import your page.
### Layouts
The themes provide the standard layouts. So, you have responsive layouts with the standard features already implemented. The screenshot below has taken from the Application Layout of the [Basic Theme](Basic-Theme.md):
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
See the [Theming](Theming.md) document for more layout options and other details.
### Layout Parts
A typical layout consists of multiple parts. The [Theming](Theming.md) system provides [menus](Navigation-Menu.md), [toolbars](Toolbars.md), [layout hooks](Layout-Hooks.md) and more to dynamically control the layout by your application and the modules you are using.
## Features
This section highlights some of the features provided by the ABP Framework for the ASP.NET Core MVC / Razor Pages UI.
### Dynamic JavaScript API Client Proxies
Dynamic JavaScript API Client Proxy system allows you to consume your server side HTTP APIs from your JavaScript client code, just like calling local functions.
**Example: Get a list of authors from the server**
````js
acme.bookStore.authors.author.getList({
maxResultCount: 10
}).then(function(result){
console.log(result.items);
});
````
`acme.bookStore.authors.author.getList` is an auto-generated function that internally makes an AJAX call to the server.
See the [Dynamic JavaScript API Client Proxies](Dynamic-JavaScript-Proxies.md) document for more.
### Bootstrap Tag Helpers
ABP makes it easier & type safe to write Bootstrap HTML.
**Example: Render a Bootstrap modal**
````html
<abp-modal>
<abp-modal-header title="Modal title" />
<abp-modal-body>
Woohoo, you're reading this text in a modal!
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Save|AbpModalButtons.Close)"></abp-modal-footer>
</abp-modal>
````
See the [Tag Helpers](Tag-Helpers/Index.md) document for more.
### Forms & Validation
ABP provides `abp-dynamic-form` and `abp-input` tag helpers to dramatically simplify to create a fully functional form that automates localization, validation and AJAX submission.
**Example: Use `abp-dynamic-form` to create a complete form based on a model**
````html
<abp-dynamic-form abp-model="Movie" submit-button="true" />
````
See the [Forms & Validation](Forms-Validation.md) document for details.
### Bundling & Minification / Client Side Libraries
ABP provides a flexible and modular Bundling & Minification system to create bundles and minify style/script files on runtime.
````html
<abp-style-bundle>
<abp-style src="/libs/bootstrap/css/bootstrap.css" />
<abp-style src="/libs/font-awesome/css/font-awesome.css" />
<abp-style src="/libs/toastr/toastr.css" />
<abp-style src="/styles/my-global-style.css" />
</abp-style-bundle>
````
Also, Client Side Package Management system offers a modular and consistent way of managing 3rd-party library dependencies.
See the [Bundling & Minification](Bundling-Minification.md) and [Client Side Package Management](Client-Side-Package-Management.md) documents.
### JavaScript APIs
[JavaScript APIs](JavaScript-API/Index.md) provides a strong abstractions to the server side localization, settings, permissions, features... etc. They also provide a simple way to show messages and **notifications** to the user.
### Modals, Alerts, Widgets and More
ABP Framework provides a lot of built-in solutions to common application requirements;
* [Widget System](Widgets.md) can be used to create reusable widgets & create dashboards.
* [Page Alerts](Page-Alerts.md) makes it easy to show alerts to the user.
* [Modal Manager](Modals.md) provides a simple way to build and use modals.
* [Data Tables](Data-Tables.md) integration makes straightforward to create data grids.
## Customization
There are a lot of ways to customize the theme and the UIs of the pre-built modules. You can override components, pages, static resources, bundles and more. See the [User Interface Customization Guide](Customization-User-Interface.md).

58
docs/en/UI/AspNetCore/Page-Header.md

@ -0,0 +1,58 @@
# ASP.NET Core MVC / Razor Pages: Page Header
`IPageLayout` service can be used to set the page title, selected menu item and the breadcrumb items for a page. It's the [theme](Theming.md)'s responsibility to render these on the page.
## IPageLayout
`IPageLayout` can be injected in any page/view to set the page header properties.
### Page Title
Page Title can be set as shown in the example below:
````csharp
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = "Book List";
}
````
* The Page Title is set to the HTML `title` tag (in addition to the [brand/application name](Branding.md)).
* The theme may render the Page Title before the Page Content (not implemented by the Basic Theme).
### Breadcrumb
> **The [Basic Theme](Basic-Theme.md) currently doesn't implement the breadcrumbs.**
Breadcrumb items can be added to the `PageLayout.Content.BreadCrumb`.
**Example: Add Language Management to the breadcrumb items.**
````
PageLayout.Content.BreadCrumb.Add("Language Management");
````
The theme then renders the breadcrumb. An example render result can be:
![breadcrumbs-example](../../images/breadcrumbs-example.png)
* The Home icon is rendered by default. Set `PageLayout.Content.BreadCrumb.ShowHome` to `false` to hide it.
* Current Page name (got from the `PageLayout.Content.Title`) is added as the last by default. Set `PageLayout.Content.BreadCrumb.ShowCurrent` to `false` to hide it.
Any item that you add is inserted between Home and Current Page items. You can add as many item as you need. `BreadCrumb.Add(...)` method gets three parameters:
* `text`: The text to show for the breadcrumb item.
* `url` (optional): A URL to navigate to, if the user clicks to the breadcrumb item.
* `icon` (optional): An icon class (like `fas fa-user-tie` for Font-Awesome) to show with the `text`.
### The Selected Menu Item
> **The [Basic Theme](Basic-Theme.md) currently doesn't implement the selected menu item since it is not applicable to the top menu which is the only option for the Basic Theme for now.**
You can set the Menu Item name related to this page:
````csharp
PageLayout.Content.MenuItemName = "BookStore.Books";
````
Menu item name should match a unique menu item name defined using the [Navigation / Menu](Navigation-Menu.md) system. In this case, it is expected from the theme to make the menu item "active" in the main menu.

4
docs/en/UI/AspNetCore/Tag-Helpers/Index.md

@ -13,7 +13,7 @@ ABP Framework also adds some **useful features** to the standard bootstrap compo
Here, the list of components those are wrapped by the ABP Framework:
* [Alerts](Alerts.md)
* [Badges](Badges.md))
* [Badges](Badges.md)
* [Blockquote](Blockquote.md)
* [Borders](Borders.md)
* [Breadcrumb](Breadcrumb.md)
@ -42,4 +42,4 @@ Here, the list of components those are wrapped by the ABP Framework:
## Dynamic Forms
**Abp Tag helpers** offer an easy way to build complete **Bootstrap forms**. See [Dynamic Forms documentation](Dynamic-Forms.md).
**Abp Tag helpers** offer an easy way to build complete **Bootstrap forms**. See [Dynamic Forms documentation](Dynamic-Forms.md).

2
docs/en/UI/AspNetCore/Theming.md

@ -406,6 +406,8 @@ The Basic Theme doesn't implement this service, but the Lepton Theme implements:
![breadcrumbs-example](../../images/breadcrumbs-example.png)
See the [Page Header](Page-Header.md) document for more.
#### Tenant Switch
The Account Layout should allow the user to switch the current tenant if the application is multi-tenant and the tenant was resolved from the cookies. See the [Basic Theme Account Layout](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml) as an example implementation.

75
docs/en/UI/AspNetCore/Toolbars.md

@ -1,3 +1,74 @@
# Toolbars
# ASP.NET Core MVC / Razor Pages UI: Toolbars
TODO
The Toolbar system is used to define **toolbars** on the user interface. Modules (or your application) can add **items** to a toolbar, then the [theme](Theming.md) renders the toolbar on the **layout**.
There is only one **standard toolbar** named "Main" (defined as a constant: `StandardToolbars.Main`). The [Basic Theme](Basic-Theme) renders the main toolbar as shown below:
![bookstore-toolbar-highlighted](../../images/bookstore-toolbar-highlighted.png)
In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here.
## Example: Add a Notification Icon
In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **view component**. So, first, create a new view component in your project:
![bookstore-notification-view-component](../../images/bookstore-notification-view-component.png)
**NotificationViewComponent.cs**
````csharp
public class NotificationViewComponent : AbpViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
return View("/Pages/Shared/Components/Notification/Default.cshtml");
}
}
````
**Default.cshtml**
````xml
<div id="MainNotificationIcon" style="color: white; margin: 8px;">
<i class="far fa-bell"></i>
</div>
````
Now, we can create a class implementing the `IToolbarContributor` interface:
````csharp
public class MyToolbarContributor : IToolbarContributor
{
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
{
if (context.Toolbar.Name == StandardToolbars.Main)
{
context.Toolbar.Items
.Insert(0, new ToolbarItem(typeof(NotificationViewComponent)));
}
return Task.CompletedTask;
}
}
````
This class adds the `NotificationViewComponent` as the first item in the `Main` toolbar.
Finally, you need to add this contributor to the `AbpToolbarOptions`, in the `ConfigureServices` of your [module](../../Module-Development-Basics.md):
````csharp
Configure<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new MyToolbarContributor());
});
````
That's all, you will see the notification icon on the toolbar when you run the application:
![bookstore-notification-icon-on-toolbar](../../images/bookstore-notification-icon-on-toolbar.png)
`NotificationViewComponent` in this sample simply returns a view without any data. In real life, you probably want to **query database** (or call an HTTP API) to get notifications and pass to the view. If you need, you can add a `JavaScript` or `CSS` file to the global [bundle](Bundling-Minification.md) for your toolbar item.
## IToolbarManager
`IToolbarManager` is used to render the toolbar. It returns the toolbar items by a toolbar name. This is generally used by the [themes](Theming.md) to render the toolbar on the layout.

2
docs/en/UI/Blazor/Localization.md

@ -1,3 +1,3 @@
# Blazor UI: Localization
# Blazor: Localization
Blazor applications can reuse the same `IStringLocalizer<T>` service that is explained in the [localization document](../../Localization.md). All the localization resources and texts available in the server side are usable in the Blazor application.

3
docs/en/UI/Blazor/Message.md

@ -0,0 +1,3 @@
# Blazor: UI Message Service
TODO

3
docs/en/UI/Blazor/Notification.md

@ -0,0 +1,3 @@
# Blazor: Notification
`UiNotificationService` is used to show toastr style notifications on the user interface. The documentation is in progress...

4
docs/en/UI/Blazor/Overall.md

@ -1,6 +1,8 @@
# Blazor UI for the ABP Framework
The detailed documentation for the Blazor UI is in progress. However, you can follow the documents below to start with the Blazor UI today.
## Getting Started
You can follow the documents below to start with the ABP Framework and the Blazor UI:
* [Get started](https://docs.abp.io/en/abp/latest/Getting-Started?UI=Blazor) with the Blazor UI for the ABP Framework.
* [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=Blazor) with the Blazor UI.

3
docs/en/UI/Blazor/Services/Notification.md

@ -1,3 +0,0 @@
# Blazor UI Notification
`UiNotificationService` is used to show toastr style notifications on the user interface. The documentation is in progress...

2
docs/en/UI/Blazor/Settings.md

@ -1,3 +1,3 @@
# Blazor UI: Settings
# Blazor: Settings
Blazor applications can reuse the same `ISettingProvider` service that is explained in the [settings document](../../Settings.md).

50
docs/en/docs-nav.json

@ -404,8 +404,12 @@
"text": "User Interface",
"items": [
{
"text": "ASP.NET Core MVC / Razor Pages",
"text": "MVC / Razor Pages",
"items": [
{
"text": "Overall",
"path": "UI/AspNetCore/Overall.md"
},
{
"text": "Navigation / Menus",
"path": "UI/AspNetCore/Navigation-Menu.md"
@ -418,10 +422,18 @@
"text": "Modals",
"path": "UI/AspNetCore/Modals.md"
},
{
"text": "Data Tables",
"path": "UI/AspNetCore/Data-Tables.md"
},
{
"text": "Page Alerts",
"path": "UI/AspNetCore/Page-Alerts.md"
},
{
"text": "Dynamic JavaScript API Client Proxies",
"path": "UI/AspNetCore/Dynamic-JavaScript-Proxies.md"
},
{
"text": "Client Side Package Management",
"path": "UI/AspNetCore/Client-Side-Package-Management.md"
@ -448,13 +460,31 @@
"text": "Widgets",
"path": "UI/AspNetCore/Widgets.md"
},
{
"text": "Toolbars",
"path": "UI/AspNetCore/Toolbars.md"
},
{
"text": "Page Header",
"path": "UI/AspNetCore/Page-Header.md"
},
{
"text": "Branding",
"path": "UI/AspNetCore/Branding.md"
},
{
"text": "Layout Hooks",
"path": "UI/AspNetCore/Layout-Hooks.md"
},
{
"text": "Theming",
"path": "UI/AspNetCore/Theming.md"
"path": "UI/AspNetCore/Theming.md",
"items": [
{
"text": "The Basic Theme",
"path": "UI/AspNetCore/Basic-Theme.md"
}
]
},
{
"text": "JavaScript API",
@ -534,8 +564,20 @@
"text": "Services",
"items": [
{
"text": "Overall",
"path": "UI/Blazor/Services/Notification.md"
"text": "Localization",
"path": "UI/Blazor/Localization.md"
},
{
"text": "Settings",
"path": "UI/Blazor/Settings.md"
},
{
"text": "Notification",
"path": "UI/Blazor/Notification.md"
},
{
"text": "Message",
"path": "UI/Blazor/Message.md"
}
]
}

BIN
docs/en/images/branding-appname.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/images/branding-nobrand.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/images/datatables-custom-render-date.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/datatables-default-render-date.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/images/datatables-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/en/images/datatables-row-actions-confirmation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/images/datatables-row-actions-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/datatables-row-actions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/en/images/example-global-styles.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

4
docs/zh-Hans/Application-Services.md

@ -353,12 +353,12 @@ public class DistrictAppService
{
}
protected override async Task DeleteByIdAsync(DistrictKey id)
protected async override Task DeleteByIdAsync(DistrictKey id)
{
await Repository.DeleteAsync(d => d.CityId == id.CityId && d.Name == id.Name);
}
protected override async Task<District> GetEntityByIdAsync(DistrictKey id)
protected async override Task<District> GetEntityByIdAsync(DistrictKey id)
{
return await AsyncQueryableExecuter.FirstOrDefaultAsync(
Repository.Where(d => d.CityId == id.CityId && d.Name == id.Name)

2
docs/zh-Hans/Authorization.md

@ -343,7 +343,7 @@ public class SystemAdminPermissionValueProvider : PermissionValueProvider
public override string Name => "SystemAdmin";
public override async Task<PermissionGrantResult>
public async override Task<PermissionGrantResult>
CheckAsync(PermissionValueCheckContext context)
{
if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")

2
docs/zh-Hans/Background-Workers.md

@ -54,7 +54,7 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
Timer.Period = 600000; //10 minutes
}
protected override async Task DoWorkAsync(
protected async override Task DoWorkAsync(
PeriodicBackgroundWorkerContext workerContext)
{
Logger.LogInformation("Starting: Setting status of inactive users...");

2
docs/zh-Hans/Blog-Posts/2020-05-08 v2_7_Release/Post.md

@ -121,7 +121,7 @@ ABP框架的[异常处理系统](https://docs.abp.io/en/abp/latest/Exception-Han
````csharp
public class MyExceptionSubscriber : ExceptionSubscriber
{
public override async Task HandleAsync(ExceptionNotificationContext context)
public async override Task HandleAsync(ExceptionNotificationContext context)
{
//TODO...
}

36
docs/zh-Hans/Customizing-Application-Modules-Overriding-Services.md

@ -76,7 +76,7 @@ public class MyIdentityUserAppService : IdentityUserAppService
{
}
public override async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
public async override Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
{
if (input.PhoneNumber.IsNullOrWhiteSpace())
{
@ -109,33 +109,33 @@ public class MyIdentityUserManager : IdentityUserManager
{
public MyIdentityUserManager(
IdentityUserStore store,
IIdentityRoleRepository roleRepository,
IIdentityRoleRepository roleRepository,
IIdentityUserRepository userRepository,
IOptions<IdentityOptions> optionsAccessor,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<IdentityUser> passwordHasher,
IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<IdentityUserManager> logger,
ICancellationTokenProvider cancellationTokenProvider) :
ILogger<IdentityUserManager> logger,
ICancellationTokenProvider cancellationTokenProvider) :
base(store,
roleRepository,
userRepository,
optionsAccessor,
passwordHasher,
userValidators,
userRepository,
optionsAccessor,
passwordHasher,
userValidators,
passwordValidators,
keyNormalizer,
errors,
services,
logger,
keyNormalizer,
errors,
services,
logger,
cancellationTokenProvider)
{
}
public override async Task<IdentityResult> CreateAsync(IdentityUser user)
public async override Task<IdentityResult> CreateAsync(IdentityUser user)
{
if (user.PhoneNumber.IsNullOrWhiteSpace())
{
@ -251,8 +251,8 @@ ObjectExtensionManager.Instance
.AddOrUpdateProperty<string>(
new[]
{
typeof(IdentityUserDto),
typeof(IdentityUserCreateDto),
typeof(IdentityUserDto),
typeof(IdentityUserCreateDto),
typeof(IdentityUserUpdateDto)
},
"SocialSecurityNumber"

4
docs/zh-Hans/Entity-Framework-Core-Migrations.md

@ -235,7 +235,7 @@ public static class BackgroundJobsDbContextModelCreatingExtensions
}
````
此u还获取选项用于更改此模块的数据库表前缀和模式,但在这里并不重要.
此扩展方法还提供了选项用于更改此模块的数据库表前缀和模式,但在这里并不重要.
最终的应用程序在 `MigrationsDbContext` 类中调用扩展方法, 因此它可以确定此 `MigrationsDbContext` 维护的数据库中包含哪些模块. 如果要创建第二个数据库并将某些模块表移动到第二个数据库,则需要有第二个`MigrationsDbContext` 类,该类仅调用相关模块的扩展方法. 下一部分将详细介绍该主题.
@ -883,4 +883,4 @@ public class BookStoreDbMigratorModule : AbpModule
## 结论
本文档说明了如何拆分数据库以及管理Entity Framework Core解决方案的数据库迁移. 简而言之,你需要为每个不同的数据库创建一个单独的迁移项目.
本文档说明了如何拆分数据库以及管理Entity Framework Core解决方案的数据库迁移. 简而言之,你需要为每个不同的数据库创建一个单独的迁移项目.

6
docs/zh-Hans/Entity-Framework-Core.md

@ -263,7 +263,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
在你想要覆盖默认仓储方法对其自定义时,这一点非常需要. 例如你可能希望自定义`DeleteAsync`方法覆盖默认实现
````csharp
public override async Task DeleteAsync(
public async override Task DeleteAsync(
Guid id,
bool autoSave = false,
CancellationToken cancellationToken = default)
@ -365,7 +365,7 @@ public class MyRepositoryBase<TEntity>
: EfCoreRepository<BookStoreDbContext, TEntity>
where TEntity : class, IEntity
{
public MyRepositoryBase(IDbContextProvider<BookStoreDbContext> dbContextProvider)
public MyRepositoryBase(IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
@ -447,4 +447,4 @@ context.Services.AddAbpDbContext<OtherDbContext>(options =>
## 另请参阅
* [实体](Entities.md)
* [实体](Entities.md)

354
docs/zh-Hans/Getting-Started-AspNetCore-Application.md

@ -1,194 +1,160 @@
## 在AspNet Core MVC Web Application中使用ABP
本教程将介绍如何开始以最少的依赖关系开始使用ABP开发.
通常情况下你需要下载一个 ***[启动模板](Getting-Started-AspNetCore-MVC-Template.md)***
### 创建一个新项目
1. 使用Visual Studio创建一个空的AspNet Core Web Application:
![](images/create-new-aspnet-core-application.png)
2. 选择空模板
![](images/select-empty-web-application.png)
你可以选择其它模板,但是我想要从一个简洁的项目演示它.
### 安装 Volo.Abp.AspNetCore.Mvc 包
Volo.Abp.AspNetCore.Mvc是ABP集成AspNet Core MVC的包,请安装它到你项目中:
````
Install-Package Volo.Abp.AspNetCore.Mvc
````
### 创建ABP模块
ABP是一个模块化框架,它需要一个**启动 (根) 模块**继承自``AbpModule``:
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace BasicAspNetCoreApplication
{
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseConfiguredEndpoints();
}
}
}
````
``AppModule`` 是应用程序启动模块的好名称(建议你的启动模块也使用这个命名).
ABP的包定义了这个模块类,模块可以依赖其它模块.在上面的代码中 ``AppModule`` 依赖于 ``AbpAspNetCoreMvcModule`` (模块存在于Volo.Abp.AspNetCore.Mvc包中). 安装新的ABP的包后添加``DependsOn``是很常见的做法.
我们在此模块类中配置ASP.NET Core管道,而不是Startup类中.
### 启动类
接下来修改启动类集成ABP模块系统:
````C#
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
````
修改``ConfigureServices``方法的返回值为``IServiceProvider``(默认是``void``).这个修改允许我们替换AspNet Core的依赖注入框架. (参阅下面的Autofac集成部分). ``services.AddApplication<AppModule>()``添加了所有模块中定义的全部服务.
``app.InitializeApplication()`` 调用 ``Configure`` 方法初始化并启动应用程序
### Hello World!
上面的应用程序没有什么功能,让我们创建一个MVC控制器实现一些功能:
````C#
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}
````
如果运行这个应用程序你会在页面中看到"Hello World!".
Derived ``HomeController`` from ``AbpController`` instead of standard ``Controller`` class. This is not required, but ``AbpController`` class has useful base properties and methods to make your development easier.
从``AbpController``派生``HomeController`` 而不是继承自``Controller``类.虽然这不是强制要求,但是``AbpController``类有很多有用的有属性和方法,使你的开发更容易.
### 使用 Autofac 依赖注入框架
虽然AspNet Core的依赖注入(DI)系统适用于基本要求,但Autofac提供了属性注入和方法拦截等高级功能,这些功能是ABP执行高级应用程序框架功能所必需的.
用Autofac取代AspNet Core的DI系统并集成到ABP非常简单.
1. 安装 Volo.Abp.Autofac 包
````
Install-Package Volo.Abp.Autofac
````
2. 添加 ``AbpAutofacModule`` 依赖
````C#
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule))] // 在模块上添加依赖AbpAutofacModule
public class AppModule : AbpModule
{
...
}
````
3. 修改在``Startup``类下的``services.AddApplication<AppModule>();``如下所示:
````C#
services.AddApplication<AppModule>(options =>
{
options.UseAutofac(); // 集成 Autofac
});
````
4. 更新 `Program.cs`代码, 不再使用`WebHost.CreateDefaultBuilder()`方法(因为它使用默认的DI容器):
````csharp
public class Program
{
public static void Main(string[] args)
{
/*
https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167
CurrentDirectoryHelpers 文件位于: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs
当升级到ASP.NET Core 3.0的时候将会删除这个类.
*/
CurrentDirectoryHelpers.SetCurrentDirectory();
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
````
### 源码
从[此处](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication)获取本教程中创建的示例项目的源代码.
# 在AspNet Core MVC Web Application中使用ABP
本教程将介绍如何开始以最少的依赖关系开始使用ABP开发.
通常情况下你需要下载一个 **[启动模板](Getting-Started-AspNetCore-MVC-Template.md)**
## 创建一个新项目
1. 使用Visual Studio 2019 (16.4.0+)创建一个新的AspNet Core Web Application:
![](images/create-new-aspnet-core-application-v2.png)
2. 配置新的项目:
![](images/select-empty-web-application-v2.png)
3. 完成创建:
![](images/create-aspnet-core-application.png)
## 安装 Volo.Abp.AspNetCore.Mvc 包
Volo.Abp.AspNetCore.Mvc是ABP集成AspNet Core MVC的包,请安装它到你项目中:
````
Install-Package Volo.Abp.AspNetCore.Mvc
````
## 创建ABP模块
ABP是一个模块化框架,它需要一个**启动 (根) 模块**继承自``AbpModule``:
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace BasicAspNetCoreApplication
{
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseConfiguredEndpoints();
}
}
}
````
``AppModule`` 是应用程序启动模块的好名称.
ABP的包定义了这个模块类,模块可以依赖其它模块.在上面的代码中 ``AppModule`` 依赖于 ``AbpAspNetCoreMvcModule`` (模块存在于[Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)包中). 安装新的ABP的包后添加``DependsOn``是很常见的做法.
我们在此模块类中配置ASP.NET Core管道,而不是Startup类中.
### 启动类
接下来修改启动类集成ABP模块系统:
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
````
``services.AddApplication<AppModule>()``添加了所有``AppModule``模块中定义的全部服务.
``Configure``方法中的``app.InitializeApplication()``完成初始化并启动应用程序.
## 运行应用程序!
启动该应用,它将按预期运行.
## 使用 Autofac 依赖注入框架
虽然AspNet Core的依赖注入(DI)系统适用于基本要求,但[Autofac](https://autofac.org/)提供了属性注入和方法拦截等高级功能,这些功能是ABP执行高级应用程序框架功能所必需的.
用Autofac取代AspNet Core的DI系统并集成到ABP非常简单.
1. 安装 [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) 包
````
Install-Package Volo.Abp.Autofac
````
2. 添加 ``AbpAutofacModule`` 依赖
````C#
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule))] // 在模块上添加依赖AbpAutofacModule
public class AppModule : AbpModule
{
...
}
````
3. 修改``Program.cs``以使用Autofac:
````C#
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace BasicAspNetCoreApplication
{
public 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<Startup>();
})
.UseAutofac(); // 添加这一行
}
}
````
## 源码
从[此处](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication)获取本教程中创建的示例项目的源代码.

2
docs/zh-Hans/How-To/Customize-SignIn-Manager.md

@ -38,7 +38,7 @@ public class CustomSignInManager : Microsoft.AspNetCore.Identity.SignInManager<V
一个好的开始是从复制[源码](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Identity/Core/src/SignInManager.cs#L638-L674)而不是从零开始. 在这个用例中我们对源码进行较少的修改,为了帮助理解概念它显式显示了方法和属性的命名空间.
````csharp
public override async Task<Microsoft.AspNetCore.Identity.ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
public async override Task<Microsoft.AspNetCore.Identity.ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
{
var auth = await Context.AuthenticateAsync(Microsoft.AspNetCore.Identity.IdentityConstants.ExternalScheme);
var items = auth?.Properties?.Items;

10
docs/zh-Hans/MongoDB.md

@ -160,7 +160,7 @@ public interface IBookRepository : IRepository<Book, Guid>
实现`IBookRepository`接口的例子:
```csharp
public class BookRepository :
public class BookRepository :
MongoDbRepository<BookStoreMongoDbContext, Book, Guid>,
IBookRepository
{
@ -200,9 +200,9 @@ context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
当你想**重写基础仓储方法**时,这一点尤为重要.例如,你想要重写`DeleteAsync`方法,以便更有效的删除实体:
```csharp
public override async Task DeleteAsync(
Guid id,
bool autoSave = false,
public async override Task DeleteAsync(
Guid id,
bool autoSave = false,
CancellationToken cancellationToken = default)
{
//TODO: 自定义实现删除方法
@ -338,4 +338,4 @@ context.Services.AddMongoDbContext<OtherMongoDbContext>(options =>
});
```
这个例子中,`OtherMongoDbContext`实现了`IBookStoreMongoDbContext`.这个特性允许你在发开的时候使用多个MongoDbContext(每个模块一个),但是运行的时候只能使有一个MongoDbContext(实现所有MongoDbContexts的所有接口)
这个例子中,`OtherMongoDbContext`实现了`IBookStoreMongoDbContext`.这个特性允许你在发开的时候使用多个MongoDbContext(每个模块一个),但是运行的时候只能使有一个MongoDbContext(实现所有MongoDbContexts的所有接口)

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

@ -84,7 +84,7 @@ namespace Acme.BookStore.Books
}
````
* ABP为实体提供了两个基本的基类: `AggregateRoot`和`Entity`. **Aggregate Root**是**[领域驱动设计](./Domain-Driven-Design.md)** 概念之一. 可以视为直接查询和处理的根实体(请参阅[实体文档](./Entities.md)).
* ABP为实体提供了两个基本的基类: `AggregateRoot`和`Entity`. **Aggregate Root**是[**领域驱动设计**](./Domain-Driven-Design.md) 概念之一. 可以视为直接查询和处理的根实体(请参阅[实体文档](./Entities.md)).
* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了一些审计属性(`CreationTime`, `CreatorId`, `LastModificationTime` 等). ABP框架自动为你管理这些属性.
* `Guid`是`Book`实体的主键类型.
@ -185,7 +185,7 @@ namespace Acme.BookStore.EntityFrameworkCore
### 添加数据迁移
启动模板使用[EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)创建和维护数据库架构. 打开菜单*工具 > NuGet包管理器*下的**程序包管理控制台 (PMC)**.
启动模板使用[EF Core Code First Migrations](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/)创建和维护数据库架构. 打开菜单*工具 > NuGet包管理器*下的**程序包管理控制台 (PMC)**.
![Open Package Manager Console](images/bookstore-open-package-manager-console.png)
@ -201,7 +201,7 @@ Add-Migration "Created_Book_Entity"
在更新数据库之前,请阅读下面的部分了解如何将一些初始数据插入到数据库.
> 如果你使用其他IDE而不是Visual Studio, 你可以使用 [`dotnet-ef]`(https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#create-a-migration) 工具.
> 如果你使用其他IDE而不是Visual Studio, 你可以使用 [`dotnet-ef`](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#create-a-migration) 工具.
{{end}}
@ -262,7 +262,7 @@ namespace Acme.BookStore
}
```
* 如果数据库中当前没有图书,则此代码使用 `IRepository<Book, Guid>`(默认为[repository](../Repositories.md)将两本书插入数据库.
* 如果数据库中当前没有图书,则此代码使用 `IRepository<Book, Guid>`(默认为[repository](../Repositories.md))将两本书插入数据库.
### 更新数据库
@ -276,7 +276,7 @@ namespace Acme.BookStore
应用程序层由两个分离的项目组成:
* `Acme.BookStore.Application.Contracts 包含你的[DTO](../Data-Transfer-Objects.md)和[应用服务](../Application-Services.md)接口.
* `Acme.BookStore.Application.Contracts` 包含你的[DTO](../Data-Transfer-Objects.md)和[应用服务](../Application-Services.md)接口.
* `Acme.BookStore.Application` 包含你的应用服务实现.
在本部分中,你将创建一个应用程序服务,使用ABP Framework的 `CrudAppService` 基类来获取,创建,更新和删除书籍.

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

@ -49,7 +49,7 @@ export class AppComponent {
yarn ng generate component my-application-layout
```
在你的布局模板(`my-layout.component.html`)中添加以下代码:
在你的布局模板(`my-application-layout.component.html`)中添加以下代码:
```html
<router-outlet></router-outlet>
@ -543,4 +543,4 @@ export class AppComponent implements OnInit {
## 下一步是什么?
- [自定义设置页面](./Custom-Setting-Page.md)
- [自定义设置页面](./Custom-Setting-Page.md)

6
docs/zh-Hans/UI/AspNetCore/Customization-User-Interface.md

@ -36,7 +36,7 @@ namespace Acme.BookStore.Web.Pages.Identity.Users
{
}
public override async Task<IActionResult> OnPostAsync()
public async override Task<IActionResult> OnPostAsync()
{
//TODO: Additional logic
await base.OnPostAsync();
@ -83,10 +83,10 @@ namespace Acme.BookStore.Web.Pages.Identity.Users
public class MyLoginModel : LoginModel
{
public MyLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions
) : base(
schemeProvider,
schemeProvider,
accountOptions)
{

131
framework/.editorconfig

@ -1,131 +0,0 @@
# Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\Projects\Volosoft\abp\framework codebase based on best match to current usage at 2.10.2020.
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]
#Core editorconfig formatting - indentation
#use soft tabs (spaces) for indentation
indent_style = space
#Formatting - indentation options
#indent switch case contents.
csharp_indent_case_contents = true
#indent switch labels
csharp_indent_switch_labels = true
#Formatting - new line options
#place catch statements on a new line
csharp_new_line_before_catch = true
#place else statements on a new line
csharp_new_line_before_else = true
#require members of object intializers to be on separate lines
csharp_new_line_before_members_in_object_initializers = true
#require braces to be on a new line for accessors, methods, lambdas, object_collection_array_initializers, control_blocks, types, and properties (also known as "Allman" style)
csharp_new_line_before_open_brace = accessors, methods, lambdas, object_collection_array_initializers, control_blocks, types, properties
#Formatting - organize using options
#sort System.* using directives alphabetically, and place them before other usings
dotnet_sort_system_directives_first = true
#Formatting - spacing options
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
#Formatting - wrapping options
#leave code block on single line
csharp_preserve_single_line_blocks = true
#Style - Code block preferences
#prefer curly braces even for one line of code
csharp_prefer_braces = true:suggestion
#Style - expression bodied member options
#prefer block bodies for constructors
csharp_style_expression_bodied_constructors = false:suggestion
#prefer block bodies for methods
csharp_style_expression_bodied_methods = false:suggestion
#prefer expression-bodied members for properties
csharp_style_expression_bodied_properties = true:suggestion
#Style - expression level options
#prefer out variables to be declared inline in the argument list of a method call when possible
csharp_style_inlined_variable_declaration = true:suggestion
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion
#Style - Expression-level preferences
#prefer default over default(T)
csharp_prefer_simple_default_expression = true:suggestion
#prefer objects to be initialized using object initializers when possible
dotnet_style_object_initializer = true:suggestion
#prefer inferred tuple element names
dotnet_style_prefer_inferred_tuple_names = true:suggestion
#Style - implicit and explicit types
#prefer var over explicit type in all cases, unless overridden by another code style rule
csharp_style_var_elsewhere = true:suggestion
#prefer var is used to declare variables with built-in system types such as int
csharp_style_var_for_built_in_types = true:suggestion
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
csharp_style_var_when_type_is_apparent = true:suggestion
#Style - language keyword and framework type options
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
#Style - modifier options
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
#Style - Modifier preferences
#when this rule is set to a list of modifiers, prefer the specified ordering.
csharp_preferred_modifier_order = public,protected,private,virtual,async,static,override,readonly,abstract:suggestion
#Style - Pattern matching
#prefer pattern matching instead of is expression with type casts
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
#Style - qualification options
#prefer fields not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_field = false:suggestion
#prefer methods not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_method = false:suggestion
#prefer properties not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_property = false:suggestion

16
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LanguageSwitch.razor

@ -5,23 +5,23 @@
@inject IJSRuntime JsRuntime
@if (_otherLanguages != null && _otherLanguages.Any())
{
<Dropdown>
<DropdownToggle Color="Color.None">
<BarDropdown>
<BarDropdownToggle>
@_currentLanguage.DisplayName
</DropdownToggle>
<DropdownMenu>
</BarDropdownToggle>
<BarDropdownMenu RightAligned="true">
@foreach (var language in _otherLanguages)
{
<DropdownItem Clicked="() => ChangeLanguageAsync(language)">@language.DisplayName</DropdownItem>
<BarDropdownItem Clicked="() => ChangeLanguageAsync(language)">@language.DisplayName</BarDropdownItem>
}
</DropdownMenu>
</Dropdown>
</BarDropdownMenu>
</BarDropdown>
}
@code {
private IReadOnlyList<LanguageInfo> _otherLanguages;
private LanguageInfo _currentLanguage;
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
var selectedLanguageName = await JsRuntime.InvokeAsync<string>(
"localStorage.getItem",

3
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor

@ -26,9 +26,6 @@
<DropdownItem Clicked="@(() => NavigateTo(menuItem.Url))">@menuItem.DisplayName</DropdownItem>
}
}
<a class="dropdown-item" href="@ServerAccountUrl">
@UiLocalizer["ManageYourAccount"]
</a>
<DropdownDivider />
<DropdownItem Clicked="BeginSignOut">Logout</DropdownItem>
</DropdownMenu>

29
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

@ -1,50 +1,33 @@
using System;
using System.Threading.Tasks;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.Http.Client;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
{
public partial class LoginDisplay : IDisposable
{
[Inject]
protected IMenuManager MenuManager { get; set; }
[Inject]
protected IStringLocalizer<AbpUiResource> UiLocalizer { get; set; }
[Inject]
protected IOptions<AbpRemoteServiceOptions> RemoteServiceOptions { get; set; }
protected ApplicationMenu Menu { get; set; }
protected IMenuManager MenuManager { get; set; }
protected string ServerUrl { get; set; }
protected string ServerAccountUrl { get; set; }
protected ApplicationMenu Menu { get; set; }
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
Menu = await MenuManager.GetAsync(StandardMenus.User);
ServerUrl = RemoteServiceOptions.Value.RemoteServices.Default?.BaseUrl?.TrimEnd('/');
ServerAccountUrl = ServerUrl + "/Account/Manage?returnUrl=" + Navigation.Uri;
Navigation.LocationChanged += OnLocationChanged;
}
protected virtual void OnLocationChanged(object sender, LocationChangedEventArgs e)
{
ServerAccountUrl = ServerUrl + "/Account/Manage?returnUrl=" + Navigation.Uri;
StateHasChanged();
}
public void Dispose()
{
Navigation.LocationChanged -= OnLocationChanged;
}
}
}
}

1
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor

@ -22,4 +22,5 @@
@Body
<UiMessageAlert />
<UiNotificationAlert />
</div>

4
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor

@ -1,8 +1,8 @@
<ul class="navbar-nav">
@foreach (var render in ToolbarItemRenders)
{
<li class="nav-item">
<BarItem>
@render
</li>
</BarItem>
}
</ul>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
private List<RenderFragment> ToolbarItemRenders { get; set; } = new List<RenderFragment>();
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
var toolbar = await ToolbarManager.GetAsync(StandardToolbars.Main);

1
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ExceptionHandling/UserExceptionInformer.cs

@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.AspNetCore.ExceptionHandling;

12
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/IUiNotificationService.cs

@ -1,12 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public interface IUiNotificationService
{
Task Info(string message);
Task Success(string message);
Task Warn(string message);
Task Error(string message);
}
}

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/SimpleUiMessageService.cs → framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Messages/SimpleUiMessageService.cs

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using Microsoft.JSInterop;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Messages
{
public class SimpleUiMessageService : IUiMessageService, ITransientDependency
{

27
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/NullUiNotificationService.cs

@ -1,27 +0,0 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public class NullUiNotificationService : IUiNotificationService, ITransientDependency
{
public Task Info(string message)
{
return Task.CompletedTask;
}
public Task Success(string message)
{
return Task.CompletedTask;
}
public Task Warn(string message)
{
return Task.CompletedTask;
}
public Task Error(string message)
{
return Task.CompletedTask;
}
}
}

22
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/AbpComponentBase.cs

@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.AspNetCore.Components.WebAssembly;
using Volo.Abp.Localization;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Users;
@ -53,6 +54,12 @@ namespace Volo.Abp.AspNetCore.Components
protected ICurrentUser CurrentUser => LazyGetRequiredService(ref _currentUser);
private ICurrentUser _currentUser;
protected IUiMessageService Message => LazyGetNonScopedRequiredService(ref _message);
private IUiMessageService _message;
protected IUiNotificationService Notify => LazyGetNonScopedRequiredService(ref _notify);
private IUiNotificationService _notify;
protected IObjectMapper ObjectMapper
{
get
@ -90,6 +97,21 @@ namespace Volo.Abp.AspNetCore.Components
return reference;
}
protected TService LazyGetNonScopedRequiredService<TService>(ref TService reference) => LazyGetNonScopedRequiredService(typeof(TService), ref reference);
protected TRef LazyGetNonScopedRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
reference = (TRef)NonScopedServices.GetRequiredService(serviceType);
}
return reference;
}
[Inject]
protected IServiceProvider NonScopedServices { get; set; }
protected virtual IStringLocalizer CreateLocalizer()
{
if (LocalizationResource != null)

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/IUiMessageService.cs → framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/IUiMessageService.cs

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/UiMessageEventArgs.cs → framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageEventArgs.cs

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/UiMessageOptions.cs → framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageOptions.cs

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/UiMessageType.cs → framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Messages/UiMessageType.cs

13
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/IUiNotificationService.cs

@ -0,0 +1,13 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public interface IUiNotificationService
{
Task Info(string message, string title = null, Action<UiNotificationOptions> options = null);
Task Success(string message, string title = null, Action<UiNotificationOptions> options = null);
Task Warn(string message, string title = null, Action<UiNotificationOptions> options = null);
Task Error(string message, string title = null, Action<UiNotificationOptions> options = null);
}
}

28
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/NullUiNotificationService.cs

@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public class NullUiNotificationService : IUiNotificationService, ITransientDependency
{
public Task Info(string message, string title = null, Action<UiNotificationOptions> options = null)
{
return Task.CompletedTask;
}
public Task Success(string message, string title = null, Action<UiNotificationOptions> options = null)
{
return Task.CompletedTask;
}
public Task Warn(string message, string title = null, Action<UiNotificationOptions> options = null)
{
return Task.CompletedTask;
}
public Task Error(string message, string title = null, Action<UiNotificationOptions> options = null)
{
return Task.CompletedTask;
}
}
}

23
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationEventArgs.cs

@ -0,0 +1,23 @@
using System;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public class UiNotificationEventArgs : EventArgs
{
public UiNotificationEventArgs(UiNotificationType notificationType, string message, string title, UiNotificationOptions options)
{
NotificationType = notificationType;
Message = message;
Title = title;
Options = options;
}
public UiNotificationType NotificationType { get; set; }
public string Message { get; }
public string Title { get; }
public UiNotificationOptions Options { get; }
}
}

20
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationOptions.cs

@ -0,0 +1,20 @@
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
/// <summary>
/// Options to override notification appearance.
/// </summary>
public class UiNotificationOptions
{
/// <summary>
/// Custom text for the Ok button.
/// </summary>
public ILocalizableString OkButtonText { get; set; }
/// <summary>
/// Custom icon for the Ok button.
/// </summary>
public object OkButtonIcon { get; set; }
}
}

10
framework/src/Volo.Abp.AspNetCore.Components/Volo/Abp/AspNetCore/Components/Notifications/UiNotificationType.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.AspNetCore.Components.WebAssembly
{
public enum UiNotificationType
{
Info,
Success,
Warning,
Error,
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
ConfigurationClient = configurationClient;
}
public override async Task<string> GetOrNullAsync(string name)
public async override Task<string> GetOrNullAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return configuration.Features.Values.GetOrDefault(name);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
{
public class AbpBreadcrumbTagHelperService : AbpTagHelperService<AbpBreadcrumbTagHelper>
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "nav";
output.Attributes.Add("aria-label", "breadcrumb");

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs

@ -19,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
L = localizer;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
public class AbpAccordionItemTagHelperService : AbpTagHelperService<AbpAccordionItemTagHelper>
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetRandomIdIfNotProvided();

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
HtmlGenerator = htmlGenerator;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetRandomIdIfNotProvided();
@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.AddClass("accordion");
output.Attributes.Add("id",TagHelper.Id);
var items = InitilizeFormGroupContentsContext(context, output);
await output.GetChildContentAsync();
@ -62,4 +62,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
}
}
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs

@ -6,7 +6,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
public class AbpCollapseBodyTagHelperService : AbpTagHelperService<AbpCollapseBodyTagHelper>
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.Attributes.AddClass("collapse");
@ -27,4 +27,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
output.Content.SetHtmlContent(innerContent);
}
}
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs

@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
_serviceProvider = serviceProvider;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var content = await output.GetChildContentAsync();
@ -60,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
protected virtual async Task<string> GetMainButtonAsync(TagHelperContext context, TagHelperOutput output, TagHelperContent content)
{
var abpButtonTagHelper = _serviceProvider.GetRequiredService<AbpButtonTagHelper>();
abpButtonTagHelper.Icon = TagHelper.Icon;
abpButtonTagHelper.Text = TagHelper.Text;
abpButtonTagHelper.IconType = TagHelper.IconType;
@ -121,7 +121,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{"aria-haspopup", "true"},
{"aria-expanded", "false"},
};
attributes.AddClass("dropdown-toggle");
attributes.AddClass("dropdown-toggle-split");
@ -142,4 +142,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
return buttonTag;
}
}
}
}

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

@ -31,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_serviceProvider = serviceProvider;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var list = InitilizeFormGroupContentsContext(context, output);
@ -144,7 +144,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
}
}
}
protected virtual void RemoveFormGroupItemsNotInModel(TagHelperContext context, TagHelperOutput output, List<FormGroupItem> items)
{
var models = GetModels(context, output);
@ -303,4 +303,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return explorer.GetAttribute<AbpRadioButton>() != null;
}
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -26,7 +26,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_tagHelperLocalizer = tagHelperLocalizer;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -35,7 +35,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_stringLocalizerFactory = stringLocalizerFactory;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output);

110
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs

@ -1,22 +1,22 @@
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{
public class AbpModalTagHelperService : AbpTagHelperService<AbpModalTagHelper>
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
var childContent = await output.GetChildContentAsync();
SetContent(context, output, childContent);
}
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{
public class AbpModalTagHelperService : AbpTagHelperService<AbpModalTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
var childContent = await output.GetChildContentAsync();
SetContent(context, output, childContent);
}
protected virtual void SetContent(TagHelperContext context, TagHelperOutput output, TagHelperContent childContent)
{
var modalContent = GetModalContentElement(context, output, childContent);
@ -24,16 +24,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
var modal = GetModal(context, output, modalDialog);
output.Content.SetHtmlContent(modal);
}
}
protected virtual TagBuilder GetModalContentElement(TagHelperContext context, TagHelperOutput output, TagHelperContent childContent)
{
var element = new TagBuilder("div");
element.AddCssClass(GetModalContentClasses());
element.InnerHtml.SetHtmlContent(childContent);
return element;
}
}
protected virtual TagBuilder GetModalDialogElement(TagHelperContext context, TagHelperOutput output, IHtmlContent innerHtml)
{
var element = new TagBuilder("div");
@ -41,8 +41,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
element.Attributes.Add("role", "document");
element.InnerHtml.SetHtmlContent(innerHtml);
return element;
}
}
protected virtual TagBuilder GetModal(TagHelperContext context, TagHelperOutput output, IHtmlContent innerHtml)
{
var element = new TagBuilder("div");
@ -61,37 +61,37 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
element.InnerHtml.SetHtmlContent(innerHtml);
return element;
}
protected virtual string GetModalClasses()
{
return "modal fade";
}
protected virtual string GetModalDialogClasses()
{
var classNames = new StringBuilder("modal-dialog");
if (TagHelper.Centered ?? false)
{
classNames.Append(" ");
classNames.Append("modal-dialog-centered");
}
if (TagHelper.Size != AbpModalSize.Default)
{
classNames.Append(" ");
classNames.Append(TagHelper.Size.ToClassName());
}
return classNames.ToString();
}
protected virtual string GetModalContentClasses()
{
return "modal-content";
}
}
protected virtual string GetModalClasses()
{
return "modal fade";
}
protected virtual string GetModalDialogClasses()
{
var classNames = new StringBuilder("modal-dialog");
if (TagHelper.Centered ?? false)
{
classNames.Append(" ");
classNames.Append("modal-dialog-centered");
}
if (TagHelper.Size != AbpModalSize.Default)
{
classNames.Append(" ");
classNames.Append(TagHelper.Size.ToClassName());
}
return classNames.ToString();
}
protected virtual string GetModalContentClasses()
{
return "modal-content";
}
protected virtual string GetDataAttributes()
{
if (TagHelper.Static == true)
@ -107,6 +107,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{
builder.Attributes.Add("data-backdrop", "static");
}
}
}
}
}
}
}

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

Loading…
Cancel
Save