Browse Source

Merge pull request #1 from abpframework/master

pull/1162/head
Nokecy 7 years ago
committed by GitHub
parent
commit
7807006f50
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      .dockerignore
  2. 9
      .gitignore
  3. 106
      abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
  4. 28
      abp_io/src/Volo.AbpWebSite.Web/CorrelationIdLogEventEnricher.cs
  5. 31
      abp_io/src/Volo.AbpWebSite.Web/Program.cs
  6. 10
      abp_io/src/Volo.AbpWebSite.Web/Startup.cs
  7. 6
      abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
  8. 3
      build-all.ps1
  9. 50
      build/build.ps1
  10. 2
      common.props
  11. 28
      docker/docker-compose.yml
  12. 1
      docker/down.ps1
  13. 18
      docker/haproxy.cfg
  14. 8
      docker/up.ps1
  15. 3
      docs/en/Audit-Logging.md
  16. 3
      docs/en/Event-Bus.md
  17. 21
      docs/en/Getting-Started-AspNetCore-Application.md
  18. 30
      docs/en/Microservice-Architecture.md
  19. 1442
      docs/en/Samples/Microservice-Demo.md
  20. 6
      docs/en/Virtual-File-System.md
  21. 13
      docs/en/docs-nav.json
  22. BIN
      docs/en/images/microservice-sample-authserver-home.png
  23. BIN
      docs/en/images/microservice-sample-authserver-login.png
  24. BIN
      docs/en/images/microservice-sample-backend-ui-permissions.png
  25. BIN
      docs/en/images/microservice-sample-backend-ui.png
  26. BIN
      docs/en/images/microservice-sample-blogservice-permission-in-database.png
  27. BIN
      docs/en/images/microservice-sample-diagram.png
  28. BIN
      docs/en/images/microservice-sample-kibana-1.png
  29. BIN
      docs/en/images/microservice-sample-kibana-2.png
  30. BIN
      docs/en/images/microservice-sample-product-module-in-solution.png
  31. BIN
      docs/en/images/microservice-sample-public-product-list.png
  32. BIN
      docs/en/images/microservice-sample-solution.png
  33. 96
      docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md
  34. 3
      docs/zh-Hans/Domain-Services.md
  35. 3
      docs/zh-Hans/Dynamic-Proxying-Interceptors.md
  36. 3
      docs/zh-Hans/Event-Bus.md
  37. 3
      docs/zh-Hans/Guid-Generation.md
  38. 30
      docs/zh-Hans/Microservice-Architecture.md
  39. 2
      docs/zh-Hans/Modules/Docs.md
  40. 2
      docs/zh-Hans/Modules/Index.md
  41. 40
      docs/zh-Hans/Samples/Microservice-Demo.md
  42. 6
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
  43. 3
      docs/zh-Hans/Unit-Of-Work.md
  44. 3
      docs/zh-Hans/Validation.md
  45. 6
      docs/zh-Hans/Virtual-File-System.md
  46. 35
      docs/zh-Hans/docs-nav.json
  47. BIN
      docs/zh-Hans/images/microservice-sample-diagram.png
  48. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  49. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
  50. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
  51. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClientExtensions.cs
  52. 70
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs
  53. 33
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs
  54. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
  55. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationSettingConfigurationDto.cs
  56. 32
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs
  57. 88
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
  58. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbItemTagHelperService.cs
  59. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselItemTagHelperService.cs
  60. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
  61. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
  62. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownTagHelperService.cs
  63. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/ModelExplorerExtensions.cs
  64. 25
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperAttributeExtensions.cs
  65. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperContextExtensions.cs
  66. 41
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs
  67. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperOutputExtensions.cs
  68. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  69. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs
  70. 67
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  71. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs
  72. 22
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
  73. 56
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  74. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs
  75. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs
  76. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs
  77. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs
  78. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs
  79. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs
  80. 44
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs
  81. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
  82. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
  83. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs
  84. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelper.cs
  85. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelperService.cs
  86. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
  87. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Popover/AbpPopoverTagHelperService.cs
  88. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs
  89. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs
  90. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs
  91. 37
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs
  92. 38
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollection.cs
  93. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Components/TenantSwitch/Default.cshtml
  94. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Components/TenantSwitch/TenantSwitchViewComponent.cs
  95. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/AbpAspNetCoreMvcUIBasicThemeModule.cs
  96. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  97. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/ContentLayout.cs
  98. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs
  99. 36
      framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs
  100. 8
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

14
.dockerignore

@ -0,0 +1,14 @@
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
.env
*/bin
*/obj
README.md
LICENSE
.vscode
.vs

9
.gitignore

@ -285,3 +285,12 @@ framework/test/Volo\.Abp\.AspNetCore\.Mvc\.UI\.Bootstrap\.Demo/package-lock\.jso
modules/blogging/app/Volo\.BloggingTestApp/package-lock\.json
templates/mvc/src/MyCompanyName\.MyProjectName\.Web/package-lock\.json
samples/MicroserviceDemo/applications/AuthServer.Host/Logs/logs.txt
samples/MicroserviceDemo/microservices/IdentityService.Host/Logs/logs.txt
samples/MicroserviceDemo/applications/BackendAdminApp.Host/Logs/logs.txt
samples/MicroserviceDemo/microservices/ProductService.Host/Logs/logs.txt
samples/MicroserviceDemo/gateways/InternalGateway.Host/Logs/logs.txt
samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Logs/logs.txt
samples/MicroserviceDemo/applications/PublicWebSite.Host/Logs/logs.txt
samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Logs/logs.txt
samples/MicroserviceDemo/microservices/BloggingService.Host/Logs/logs.txt

106
abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs

@ -8,13 +8,13 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Modularity;
using Volo.Abp.AspNetCore.Mvc.UI;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
@ -22,11 +22,14 @@ using Volo.Abp.Identity;
using Volo.Abp.Identity.Web;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.Threading;
using Volo.Abp.UI;
using Volo.Abp.VirtualFileSystem;
using Volo.AbpWebSite.Bundling;
using Volo.Blogging;
using Volo.Blogging.Files;
using Volo.Docs;
namespace Volo.AbpWebSite
@ -41,6 +44,8 @@ namespace Volo.AbpWebSite
typeof(AbpAccountWebModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpIdentityWebModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(BloggingApplicationModule),
typeof(BloggingWebModule)
)]
@ -51,24 +56,34 @@ namespace Volo.AbpWebSite
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureLanguages(context.Services);
ConfigureDatabaseServices(context.Services, configuration);
ConfigureVirtualFileSystem(context.Services, hostingEnvironment);
ConfigureBundles(context.Services);
ConfigureTheme(context.Services);
ConfigureLanguages();
ConfigureDatabaseServices(configuration);
ConfigureVirtualFileSystem(hostingEnvironment);
ConfigureBundles();
ConfigureTheme();
ConfigureBlogging(hostingEnvironment);
}
private static void ConfigureLanguages(IServiceCollection services)
private void ConfigureBlogging(IHostingEnvironment hostingEnvironment)
{
services.Configure<AbpLocalizationOptions>(options =>
Configure<BlogFileOptions>(options =>
{
options.FileUploadLocalFolder = Path.Combine(hostingEnvironment.WebRootPath, "files");
options.FileUploadUrlRoot = "/files/";
});
}
private void ConfigureLanguages()
{
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("en-US", "en-US", "English"));
});
}
private static void ConfigureBundles(IServiceCollection services)
private void ConfigureBundles()
{
services.Configure<BundlingOptions>(options =>
Configure<BundlingOptions>(options =>
{
options
.StyleBundles
@ -91,40 +106,40 @@ namespace Volo.AbpWebSite
});
}
private static void ConfigureDatabaseServices(IServiceCollection services, IConfigurationRoot configuration)
private void ConfigureDatabaseServices(IConfigurationRoot configuration)
{
services.Configure<DbConnectionOptions>(options =>
Configure<DbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = configuration.GetConnectionString("Default");
});
services.Configure<AbpDbContextOptions>(options =>
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
}
private static void ConfigureVirtualFileSystem(IServiceCollection services, IHostingEnvironment hostingEnvironment)
private void ConfigureVirtualFileSystem(IHostingEnvironment hostingEnvironment)
{
if (hostingEnvironment.IsDevelopment())
{
services.Configure<VirtualFileSystemOptions>(options =>
Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.ReplaceEmbeddedByPyhsical<AbpUiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<AbpAspNetCoreMvcUiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<AbpAspNetCoreMvcUiBootstrapModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<AbpAspNetCoreMvcUiThemeSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<DocsDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<DocsWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<BloggingWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPyhsical<AbpAccountWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}account{0}src{0}Volo.Abp.Account.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<AbpUiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<AbpAspNetCoreMvcUiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<AbpAspNetCoreMvcUiBootstrapModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<AbpAspNetCoreMvcUiThemeSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<DocsDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<DocsWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<BloggingWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<AbpAccountWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}account{0}src{0}Volo.Abp.Account.Web", Path.DirectorySeparatorChar)));
});
}
}
private void ConfigureTheme(IServiceCollection services)
private void ConfigureTheme()
{
services.Configure<ThemingOptions>(options =>
Configure<ThemingOptions>(options =>
{
options.Themes.Add<AbpIoTheme>();
options.DefaultThemeName = AbpIoTheme.Name;
@ -136,6 +151,8 @@ namespace Volo.AbpWebSite
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
app.UseCorrelationId();
app.UseAbpRequestLocalization();
if (env.IsDevelopment())
@ -158,29 +175,28 @@ namespace Volo.AbpWebSite
app.UseVirtualFiles();
app.UseAuthentication();
//TODO: Create an extension method!
app.UseMvc(routes =>
{
routes.MapRoute(
name: "defaultWithArea",
template: "{area}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseMvcWithDefaultRouteAndArea();
AsyncHelper.RunSync(async () =>
using (var scope = context.ServiceProvider.CreateScope())
{
await context.ServiceProvider
.GetRequiredService<IIdentityDataSeeder>()
.SeedAsync(
"1q2w3E*",
IdentityPermissions.GetAll()
.Union(BloggingPermissions.GetAll())
);
});
AsyncHelper.RunSync(async () =>
{
await scope.ServiceProvider
.GetRequiredService<IIdentityDataSeeder>()
.SeedAsync(
"1q2w3E*"
);
await scope.ServiceProvider
.GetRequiredService<IPermissionDataSeeder>()
.SeedAsync(
RolePermissionValueProvider.ProviderName,
"admin",
IdentityPermissions.GetAll().Union(BloggingPermissions.GetAll())
);
});
}
}
}
}

28
abp_io/src/Volo.AbpWebSite.Web/CorrelationIdLogEventEnricher.cs

@ -0,0 +1,28 @@
using Serilog.Core;
using Serilog.Events;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Tracing;
namespace Volo.AbpWebSite
{
//This is for trial for now
public class CorrelationIdLogEventEnricher : ILogEventEnricher, ITransientDependency
{
private readonly ICorrelationIdProvider _correlationIdProvider;
public CorrelationIdLogEventEnricher(ICorrelationIdProvider correlationIdProvider)
{
_correlationIdProvider = correlationIdProvider;
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
logEvent.AddOrUpdateProperty(
new LogEventProperty(
"CorrelationId",
new ScalarValue("CorrId:" + _correlationIdProvider.Get())
)
);
}
}
}

31
abp_io/src/Volo.AbpWebSite.Web/Program.cs

@ -1,13 +1,37 @@
using System.IO;
using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Serilog;
using Serilog.Events;
namespace Volo.AbpWebSite
{
public class Program
{
public static void Main(string[] args)
public static int Main(string[] args)
{
BuildWebHostInternal(args).Run();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() //TODO: Should be configurable!
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.File("Logs/logs.txt")
.CreateLogger();
try
{
Log.Information("Starting web host.");
BuildWebHostInternal(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
internal static IWebHost BuildWebHostInternal(string[] args) =>
@ -16,6 +40,7 @@ namespace Volo.AbpWebSite
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseSerilog()
.Build();
}
}

10
abp_io/src/Volo.AbpWebSite.Web/Startup.cs

@ -3,7 +3,6 @@ using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Volo.Abp;
namespace Volo.AbpWebSite
@ -23,15 +22,6 @@ namespace Volo.AbpWebSite
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory
.AddConsole()
.AddDebug()
.AddSerilog(new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.File("Logs/logs.txt")
.CreateLogger()
);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
app.InitializeApplication();

6
abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj

@ -15,7 +15,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
</ItemGroup>
@ -31,6 +31,8 @@
<ProjectReference Include="..\..\..\modules\blogging\src\Volo.Blogging.Application\Volo.Blogging.Application.csproj" />
<ProjectReference Include="..\..\..\modules\identity\src\Volo.Abp.Identity.Application\Volo.Abp.Identity.Application.csproj" />
<ProjectReference Include="..\..\..\modules\identity\src\Volo.Abp.Identity.Web\Volo.Abp.Identity.Web.csproj" />
<ProjectReference Include="..\..\..\modules\identity\src\Volo.Abp.PermissionManagement.Domain.Identity\Volo.Abp.PermissionManagement.Domain.Identity.csproj" />
<ProjectReference Include="..\..\..\modules\permission-management\src\Volo.Abp.PermissionManagement.Application\Volo.Abp.PermissionManagement.Application.csproj" />
<ProjectReference Include="..\..\..\modules\account\src\Volo.Abp.Account.Web\Volo.Abp.Account.Web.csproj" />
</ItemGroup>
@ -38,7 +40,7 @@
<Content Include=".well-known/README.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Pages\*.js" >
<Content Include="Pages\*.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Pages\*.css" />

3
build-all.ps1

@ -20,7 +20,8 @@ $solutionPaths = (
"abp_io",
"templates/module",
"templates/service",
"templates/mvc"
"templates/mvc",
"samples/MicroserviceDemo"
)
# Build all solutions

50
build/build.ps1

@ -1,50 +0,0 @@
# COMMON PATHS
$buildFolder = (Get-Item -Path "./" -Verbose).FullName
$slnFolder = Join-Path $buildFolder "../"
$outputFolder = Join-Path $buildFolder "outputs"
$abpDeskFolder = Join-Path $slnFolder "src/AbpDesk"
$abpDeskWebFolder = Join-Path $abpDeskFolder "AbpDesk.Web.Mvc"
## CLEAR ######################################################################
Remove-Item $outputFolder -Force -Recurse
New-Item -Path $outputFolder -ItemType Directory
## RESTORE NUGET PACKAGES #####################################################
Set-Location $slnFolder
dotnet restore
## PUBLISH ASPDESK WEB ########################################################
Set-Location $abpDeskWebFolder
dotnet publish --output (Join-Path $outputFolder "AbpDesk/Web")
New-Item -Path (Join-Path $outputFolder "AbpDesk/Web/PlugIns") -ItemType Directory
Copy-Item (Join-Path $abpDeskFolder "Web_PlugIns/*") (Join-Path $outputFolder "AbpDesk/Web/PlugIns/")
## PUBLISH IDENTITY HTTP API HOST #############################################
Set-Location (Join-Path $slnFolder "src/Volo.Abp.Identity.HttpApi.Host")
dotnet publish --output (Join-Path $outputFolder "AbpIdentity/HttpApiHost")
## CREATE DOCKER IMAGES #######################################################
Set-Location (Join-Path $outputFolder "AbpDesk/Web")
docker rmi abpdesk/web -f
docker build -t abpdesk/web .
Set-Location (Join-Path $outputFolder "AbpIdentity/HttpApiHost")
docker rmi abpidentity/httpapihost -f
docker build -t abpidentity/httpapihost .
## DOCKER COMPOSE FILES #######################################################
Copy-Item (Join-Path $slnFolder "docker/*.*") $outputFolder
## FINALIZE ###################################################################
Set-Location $outputFolder

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.12.0</Version>
<Version>0.13.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

28
docker/docker-compose.yml

@ -1,28 +0,0 @@
version: '2'
services:
mongodb:
image: tutum/mongodb
environment:
- AUTH=no
ports:
- "27017:27017"
- "28017:28017"
abpidentity_httpapihost:
image: abpidentity/httpapihost
environment:
- ASPNETCORE_ENVIRONMENT=Staging
abpdesk_web:
image: abpdesk/web
environment:
- ASPNETCORE_ENVIRONMENT=Staging
load_balancer:
image: haproxy:1.7.1
volumes:
- "./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg"
ports:
- "9005:8080"

1
docker/down.ps1

@ -1 +0,0 @@
docker-compose down -v --rmi local

18
docker/haproxy.cfg

@ -1,18 +0,0 @@
global
maxconn 4096
defaults
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
listen http-in
bind *:8080
server web-1 outputs_abpdesk_web_1:80
server web-2 outputs_abpdesk_web_2:80
stats enable
stats uri /haproxy
stats refresh 1s

8
docker/up.ps1

@ -1,8 +0,0 @@
docker rm $(docker ps -aq)
docker-compose up -d mongodb
docker-compose up -d abpidentity_httpapihost
docker-compose up -d abpdesk_web
sleep 2
docker-compose scale abpdesk_web=2
sleep 2
docker-compose up -d load_balancer

3
docs/en/Audit-Logging.md

@ -0,0 +1,3 @@
# Audit Logging
TODO

3
docs/en/Event-Bus.md

@ -0,0 +1,3 @@
# Event Bus
TODO

21
docs/en/Getting-Started-AspNetCore-Application.md

@ -152,6 +152,27 @@ services.AddApplication<AppModule>(options =>
});
````
4. Update `Program.cs` to not use the `WebHost.CreateDefaultBuilder()` method since it uses the default DI container:
````csharp
public class Program
{
public static void Main(string[] args)
{
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
````
## Source Code
Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication).

30
docs/en/Microservice-Architecture.md

@ -0,0 +1,30 @@
# Microservice Architecture
*"Microservices are a software development technique—a variant of the **service-oriented architecture** (SOA) architectural style that structures an application as a collection of **loosely coupled services**. In a microservices architecture, services are **fine-grained** and the protocols are **lightweight**. The benefit of decomposing an application into different smaller services is that it improves **modularity**. This makes the application easier to understand, develop, test, and become more resilient to architecture erosion. It **parallelizes development** by enabling small autonomous teams to **develop, deploy and scale** their respective services independently. It also allows the architecture of an individual service to emerge through **continuous refactoring**. Microservices-based architectures enable **continuous delivery and deployment**."*
— [Wikipedia](https://en.wikipedia.org/wiki/Microservices)
## Introduction
One of the major goals of the ABP framework is to provide a convenient infrastructure to create microservice solutions. To make this possible,
* Provides a [module system](Module-Development-Basics.md) that allows you to split your application into modules where each module may have its own database, entities, services, APIs, UI components/pages... etc.
* Offers an [architectural model](Best-Practices/Module-Architecture.md) to develop your modules to be compatible to microservice development and deployment.
* Provides [best practices guide](Best-Practices/Index.md) to develop your module standards-compliance.
* Provides base infrastructure to implement [Domain Driven Design](Domain-Driven-Design.md) in your microservices.
* Provide services to [automatically create REST-style APIs](AspNetCore/Auto-API-Controllers.md) from your application services.
* Provide services to [automatically create C# API clients](AspNetCore/Dynamic-CSharp-API-Clients.md) that makes easy to consume your services from another service/application.
* Provides a [distributed event bus](Event-Bus.md) to communicate your services.
* Provides many other services to make your daily development easier.
## Microservice for New Applications
One common advise to start a new solution is **always to start with a monolith**, keep it modular and split into microservices once the monolith becomes a problem. This makes your progress fast in the beginning especially if your team is small and you don't want to deal with challanges of the microservice architecture.
However, developing such a well-modular application can be a problem since it is **hard to keep modules isolated** from each other as you would do it for microservices (see [Stefan Tilkov's article](https://martinfowler.com/articles/dont-start-monolith.html) about that). Microservice architecture naturally forces you to develop well isolated services, but in a modular monolithic application it's easy to tight couple modules to each other and design **weak module boundaries** and API contracts.
ABP can help you in that point by oferring a **microservice-compatible, strict module architecture** where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application. See the [module development best practice guide](Best-Practices/Index.md) that offers a **microservice-first module design**. All [standard ABP modules](https://github.com/abpframework/abp/tree/master/modules) are developed based on this guide. So, you can use these modules by embedding into your monolithic solution or deploy them separately and use via remote APIs. They can share a single database or can have their own database based on your simple configuration.
## Microservice Demo Solution
The [sample microservice solution](Samples/Microservice-Demo.md) demonstrates a complete microservice solution based on the ABP framework.

1442
docs/en/Samples/Microservice-Demo.md

File diff suppressed because it is too large

6
docs/en/Virtual-File-System.md

@ -108,7 +108,7 @@ Embedding a file into a module assembly and being able to use it from another pr
Let's assume that you're developing a module that contains an embedded JavaScript file. Whenever you change this file you must re-compile the project, re-start the application and refresh the browser page to take the change. Obviously, this is very time consuming and tedious.
What is needed is the ability for the application to directly use the physical file at development time and a have a browser refresh reflect any change made in the JavaScript file. The `ReplaceEmbeddedByPyhsical` method makes all this possible.
What is needed is the ability for the application to directly use the physical file at development time and a have a browser refresh reflect any change made in the JavaScript file. The `ReplaceEmbeddedByPhysical` method makes all this possible.
The example below shows an application that depends on a module (`MyModule`) that itself contains embedded files. The application can reach the source code of the module at development time.
@ -124,8 +124,8 @@ public class MyWebAppModule : AbpModule
{
Configure<VirtualFileSystemOptions>(options =>
{
//ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project
options.FileSets.ReplaceEmbeddedByPyhsical<MyModule>(
//ReplaceEmbeddedByPhysical gets the root folder of the MyModule project
options.FileSets.ReplaceEmbeddedByPhysical<MyModule>(
Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}MyModuleProject", Path.DirectorySeparatorChar))
);
});

13
docs/en/docs-nav.json

@ -256,10 +256,23 @@
}
]
},
{
"text": "Samples",
"items": [
{
"text": "Microservice Demo",
"path": "Samples/Microservice-Demo.md"
}
]
},
{
"text": "Application Modules",
"path": "Modules/Index.md"
},
{
"text": "Microservice Architecture",
"path": "Microservice-Architecture.md"
},
{
"text": "Testing"
},

BIN
docs/en/images/microservice-sample-authserver-home.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/images/microservice-sample-authserver-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/microservice-sample-backend-ui-permissions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/en/images/microservice-sample-backend-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/en/images/microservice-sample-blogservice-permission-in-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
docs/en/images/microservice-sample-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/en/images/microservice-sample-kibana-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
docs/en/images/microservice-sample-kibana-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/en/images/microservice-sample-product-module-in-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/microservice-sample-public-product-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/images/microservice-sample-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

96
docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md

@ -7,15 +7,15 @@ ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).
你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如:
````csharp
public interface IBookService : IApplicationService
public interface IBookAppService : IApplicationService
{
Task<List<BookDto>> GetListAsync();
}
````
你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookService`完全满足这个条件.
为了能自动被发现,你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookAppService`完全满足这个条件.
在你的服务中实现这个类,你可以使用[Auto API Controller](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点.
在你的服务中实现这个类,你可以使用[auto API controller system](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点.
## 客户端代理生成
@ -45,13 +45,6 @@ public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//配置远程端点
context.Services.Configure<RemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:53929/");
});
//创建动态客户端代理
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly
@ -60,10 +53,24 @@ public class MyClientAppModule : AbpModule
}
````
`RemoteServiceOptions`被用来为远程服务配置端点(本例设置了默认的端点,当然你也可以拥有不同的服务端点供不同的客户端使用.参考本文"多个远程服务端点"小节).
`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类.
### Endpoint配置
`appsettings.json`文件中的`RemoteServices`节点被用来设置默认的服务地址.下面是最简单的配置:
````
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
}
}
}
````
查看下面的"RemoteServiceOptions"章节获取更多详细配置.
## 使用
可以很直接地使用.只需要在你的客户端程序中注入服务接口:
@ -71,9 +78,9 @@ public class MyClientAppModule : AbpModule
````csharp
public class MyService : ITransientDependency
{
private readonly IBookService _bookService;
private readonly IBookAppService _bookService;
public MyService(IBookService bookService)
public MyService(IBookAppService bookService)
{
_bookService = bookService;
}
@ -89,38 +96,32 @@ public class MyService : ITransientDependency
}
````
本例注入了上面定义的`IBookService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用.
本例注入了上面定义的`IBookAppService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用.
## 详细配置
### IHttpClientProxy接口
### RemoteServiceOptions
你可以像上面那样注入`IBookAppService`来使用客户端代理,也可以注入`IHttpClientProxy<IBookAppService>`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy<T>`接口的`Service`属性.
你可以像上面展示的那样配置`RemoteServiceOptions`.也可以从`appsettings.json`文件中读取.在你的`appsettings.json`文件中添加`RemoteServices`节点:
## 配置
````json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
}
}
}
````
### RemoteServiceOptions
然后你可以像下面这样将`IConfigurationRoot`实例直接传递到`Configure<RemoteServiceOptions>()`方法中:
默认情况下`RemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如:
````csharp
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
context.Services.Configure<RemoteServiceOptions>(configuration);
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<RemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:53929/");
});
//...
}
````
这种方式对于不修改代码来改变配置是非常有用的.
#### 多个远程服务端点
### 多个远程服务端点
上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点:
@ -137,10 +138,6 @@ context.Services.Configure<RemoteServiceOptions>(configuration);
}
````
下一节学习如何使用这个新的端点.
### AddHttpClientProxies方法
`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字:
````csharp
@ -150,4 +147,19 @@ context.Services.AddHttpClientProxies(
);
````
`remoteServiceName`参数会匹配通过`RemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点.
`remoteServiceName`参数会匹配通过`RemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点.
### 作为默认服务
当你为`IBookAppService`创建了一个服务代理,你可以直接注入`IBookAppService`来使用代理客户端(像上面章节中将的那样).你可以传递`asDefaultService:false`到`AddHttpClientProxies`方法来禁用此功能.
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
asDefaultServices: false
);
````
如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用`asDefaultServices:false`
> 如果你禁用了`asDefaultService`,你只能使用`IHttpClientProxy<T>`接口去使用客户端代理.(参见上面的相关章节).

3
docs/zh-Hans/Domain-Services.md

@ -0,0 +1,3 @@
# ABP Documentation
待添加

3
docs/zh-Hans/Dynamic-Proxying-Interceptors.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
待添加

3
docs/zh-Hans/Event-Bus.md

@ -0,0 +1,3 @@
# Event Bus
TODO

3
docs/zh-Hans/Guid-Generation.md

@ -0,0 +1,3 @@
## Guid 生成
待添加

30
docs/zh-Hans/Microservice-Architecture.md

@ -0,0 +1,30 @@
# 微服务架构
*"作为**面向服务架构**(SOA)的一个变体,微服务是一种将应用程序分解成**松散耦合服务**的新型架构风格. 通过**细粒度**的服务和**轻量级**的协议,微服务提供了更多的**模块化**,使应用程序更容易理解,开发,测试,并且更容易抵抗架构侵蚀. 它使小型团队能够**开发,部署和扩展**各自的服务,实现开发的**并行化**.它还允许通过**连续重构**形成单个服务的架构. 基于微服务架构可以实现**持续交付和部署**."*
— [维基百科](https://zh.wikipedia.org/wiki/Microservices)
## 介绍
ABP框架的主要目标之一就是提供**便捷的基础设施来创建微服务解决方案**. 我们做了以下工作:
* 提供[模块系统](Module-Development-Basics.md),允许将应用程序拆分为模块,其中每个模块可以拥有自己的数据库,实体,服务,API,UI组件/页面....等.
* 提供[架构模型](Best-Practices/Module-Architecture.md)来开发模块,与微服务开发和部署兼容.
* 提供[最佳实践指南](Best-Practices/Index.md)制定模块开发标准.
* 提供基础设施来实现微服务中的[领域驱动设计](Domain-Driven-Design.md).
* 提供从应用程序服务[自动生成REST风格的API](AspNetCore/Auto-API-Controllers.md)的服务.
* 提供[自动创建C#API客户端](AspNetCore/Dynamic-CSharp-API-Clients.md)服务,以便从其他服务/应用程序使用你服务.
* 提供[分布式事件总线](Event-Bus.md)用于服务通信.
* 提供更多其他服务,使日常开发更加简便.
## 在新应用程序中使用微服务
开始一个新解决方案建议**始终从单体开始**, 保持模块化,在单体成为问题时将其拆分为微服务.这使初期进度会很快,特别是如果你的团队人数不多,并且不想处理微服务架构带来的各种挑战.
然而开发一个良好的模块化应用程序不是那么简单,因为很难像微服务那样**保持模块之间的隔离** (参阅 [Stefan Tilkov的文章](https://martinfowler.com/articles/dont-start-monolith.html)). 微服务架构会自然的让你开发隔离的服务,但是在模块化的单体应用程序中,模块很容易彼此紧密耦合并设计出**弱模块边界**和API约定.
ABP可以帮助你,它提供了与**与微服务兼容的严格模块架构** 在这个架构中你的模块被分割成多个层/项目,在自己的VS解决方案中进行开发,该解决方案完成独立于其它模块. 这种方式开发的模块是一种天然的微服务,但是它可以很容易的插入到单体应用程序中. 请参阅**微服务优先的模块设计**的[模块开发最佳实践指南](Best-Practices/Index.md). 所有[标准的ABP模块](https://github.com/abpframework/abp/tree/master/modules)都是基于本指南开发的. 因此你可以将这些模块嵌入到单体解决方案中使用它们,也可以单独部署通过远程API调用. 它们可以共享一个数据库,也可以通过简单配置使用自己的数据库.
## 微服务解决方案示例
[微服务解决方案示例](Samples/Microservice-Demo.md)演示了基于ABP框架的完整的微服务的解决方案.

2
docs/zh-Hans/Modules/Docs.md

@ -54,7 +54,7 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
现在一个空的ABP项目已经创建完成! 现在你可以运行项目并且查看网站.
输入用户名 `admin` 密码 `1q2w3E*`到网站.
输入用户名 `admin` 密码 `1q2w3E*`到网站.
### 2- 引用文档模块包

2
docs/zh-Hans/Modules/Index.md

@ -11,7 +11,7 @@ ABP是一个 **模块化的应用程序框架** 由十多个 **nuget packages**
有一些由ABP社区开发和维护的 **开源免费** 的应用程序模块:
* **Account**: 用于用户登/注册应用程序.
* **Account**: 用于用户登/注册应用程序.
* **Audit Logging**: 用于将审计日志持久化到数据库.
* **Background Jobs**: 用于在使用默认后台作业管理器时保存后台作业.
* **Blogging**: 用于创建精美的博客. ABP的[博客](https://abp.io/blog/abp/) 就使用了此模块.

40
docs/zh-Hans/Samples/Microservice-Demo.md

@ -0,0 +1,40 @@
# 微服务解决方案示例
*"作为**面向服务架构**(SOA)的一个变体,微服务是一种将应用程序分解成**松散耦合服务**的新型架构风格. 通过**细粒度**的服务和**轻量级**的协议,微服务提供了更多的**模块化**,使应用程序更容易理解,开发,测试,并且更容易抵抗架构侵蚀. 它使小型团队能够**开发,部署和扩展**各自的服务,实现开发的**并行化**.它还允许通过**连续重构**形成单个服务的架构. 基于微服务架构可以实现**持续交付和部署**."*
— [维基百科](https://zh.wikipedia.org/wiki/Microservices)
## 介绍
ABP框架的主要目标之一就是提供[便捷的基础设施来创建微服务解决方案](../Microservice-Architecture.md).
此示例演示了一个简单而完整的微服务解决方案;
* 拥有多个可独立可单独部署的**微服务**.
* 多个**Web应用程序**, 每一个都使用不同的API网关.
* 使用[Ocelot](https://github.com/ThreeMammals/Ocelot)库开发了多个**网关** / BFFs ([用于前端的后端](https://docs.microsoft.com/zh-cn/azure/architecture/patterns/backends-for-frontends)).
* 包含使用[IdentityServer](https://identityserver.io/)框架开发的 **身份认证服务**. 它也是一个带有UI的SSO(单点登陆)应用程序.
* 有**多个数据库**. 一些微服务有自己的数据库,也有一些服务/应用程序共享同一个数据库(以演示不同的用例).
* 有不同类型的数据库: **SQL Server** (与 **Entity Framework Core** ORM) 和 **MongoDB**.
* 有一个**控制台应用程序**使用身份验证展示使用服务最简单的方法.
* 使用[Redis](https://redis.io/)做**分布式缓存**.
* 使用[RabbitMQ](https://www.rabbitmq.com/)做服务间的**消息**传递.
* 使用[Kubernates](https://kubernetes.io/)**部署**和运行所有的服务和应用程序.
下图显示了该系统:
![microservice-sample-diagram](../images/microservice-sample-diagram.png)
### 源码
你可以从[GitHub仓库](https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo)获取源码.
### 状态
此示例仍处于开发阶段,尚未完成.
## 微服务
### 身份认证服务
...

6
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md

@ -1,6 +1,6 @@
## ASP.NET Core MVC Tutorial - Part III
## ASP.NET Core MVC 教程 - 第三章
### About this Tutorial
### 关于本教程
这是本教程所有章节中的第三章.下面是所有的章节:
@ -214,4 +214,4 @@ public async Task Should_Not_Create_A_Book_Without_Name()
### 测试 Web 页面
TODO
TODO

3
docs/zh-Hans/Unit-Of-Work.md

@ -0,0 +1,3 @@
## Unit of Work
待添加

3
docs/zh-Hans/Validation.md

@ -0,0 +1,3 @@
## Validation
待添加

6
docs/zh-Hans/Virtual-File-System.md

@ -109,7 +109,7 @@ public class MyService
假设你正在开发一个包含嵌入式JavaScript文件的模块. 当你更改文件时, 你必须重新编译项目, 重新启动应用程序并刷新浏览器页面以进行更改. 显然, 这是非常耗时和乏味的.
我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. `ReplaceEmbeddedByPyhsical` 方法使其成为可能.
我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. `ReplaceEmbeddedByPhysical` 方法使其成为可能.
下面的示例展示了应用程序依赖于包含嵌入文件的模块("MyModule"), 并且应用程序可以在开发过程中直接使用模块的源代码.
@ -125,8 +125,8 @@ public class MyWebAppModule : AbpModule
{
Configure<VirtualFileSystemOptions>(options =>
{
//ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project
options.FileSets.ReplaceEmbeddedByPyhsical<MyModule>(
//ReplaceEmbeddedByPhysical gets the root folder of the MyModule project
options.FileSets.ReplaceEmbeddedByPhysical<MyModule>(
Path.Combine(hostingEnvironment.ContentRootPath, "..\\MyModuleProject")
);
});

35
docs/zh-Hans/docs-nav.json

@ -16,11 +16,11 @@
"text": "从空项目开始",
"items": [
{
"text": "使用Console Application",
"text": "使用ASP.NET Core Web Application",
"path": "Getting-Started-AspNetCore-Application.md"
},
{
"text": "使用 ASP.NET Core Web Application",
"text": "使用Console Application",
"path": "Getting-Started-Console-Application.md"
}
]
@ -67,7 +67,8 @@
"path": "Exception-Handling.md"
},
{
"text": "验证"
"text": "验证",
"path": "Validation.md"
},
{
"text": "授权"
@ -160,7 +161,8 @@
"path": "Repositories.md"
},
{
"text": "领域服务"
"text": "领域服务",
"path": "Domain-Services.md"
},
{
"text": "规约"
@ -171,13 +173,15 @@
"text": "应用服务层",
"items": [
{
"text": "应用服务"
"text": "应用服务",
"path": "Application-Services.md"
},
{
"text": "数据传输对象(DTO)"
},
{
"text": "工作单元"
"text": "工作单元",
"path": "Unit-Of-Work.md"
}
]
}
@ -188,7 +192,7 @@
"items": [
{
"text": "API",
"items": [
"items": [
{
"text": "自动API控制器",
"path": "AspNetCore/Auto-API-Controllers.md"
@ -254,6 +258,23 @@
}
]
},
{
"text": "示例",
"items": [
{
"text": "微服务示例",
"path": "Samples/Microservice-Demo.md"
}
]
},
{
"text": "应用模块",
"path": "Modules/Index.md"
},
{
"text": "微服务架构",
"path": "Microservice-Architecture.md"
},
{
"text": "测试"
},

BIN
docs/zh-Hans/images/microservice-sample-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

1
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj

@ -17,6 +17,7 @@
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
</ItemGroup>
</Project>

9
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Client
@ -8,7 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
[DependsOn(
typeof(AbpHttpClientModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpCachingModule)
typeof(AbpCachingModule),
typeof(AbpLocalizationModule)
)]
public class AbpAspNetCoreMvcClientModule : AbpModule
{
@ -21,6 +23,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
RemoteServiceName,
asDefaultServices: false
);
Configure<AbpLocalizationOptions>(options =>
{
options.GlobalContributors.Add<RemoteLocalizationContributor>();
});
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
@ -45,7 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
async () => await Proxy.Service.GetAsync(),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60) //TODO: Should be configurable. Default value should be higher (5 mins would be good).
}
);
@ -59,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
protected virtual string CreateCacheKey()
{
return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}";
return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}_{CultureInfo.CurrentUICulture.Name}";
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClientExtensions.cs

@ -0,0 +1,13 @@
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public static class CachedApplicationConfigurationClientExtensions
{
public static ApplicationConfigurationDto Get(this ICachedApplicationConfigurationClient client)
{
return AsyncHelper.RunSync(client.GetAsync);
}
}
}

70
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs

@ -0,0 +1,70 @@
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class RemoteLocalizationContributor : ILocalizationResourceContributor
{
private LocalizationResource _resource;
private ICachedApplicationConfigurationClient _applicationConfigurationClient;
private ILogger<RemoteLocalizationContributor> _logger;
public void Initialize(LocalizationResourceInitializationContext context)
{
_resource = context.Resource;
_applicationConfigurationClient = context.ServiceProvider.GetRequiredService<ICachedApplicationConfigurationClient>();
_logger = context.ServiceProvider.GetService<ILogger<RemoteLocalizationContributor>>()
?? NullLogger<RemoteLocalizationContributor>.Instance;
}
public LocalizedString GetOrNull(string cultureName, string name)
{
var resource = GetResourceOrNull();
if (resource == null)
{
return null;
}
var value = resource.GetOrDefault(name);
if (value == null)
{
return null;
}
return new LocalizedString(name, value);
}
public void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary)
{
var resource = GetResourceOrNull();
if (resource == null)
{
return;
}
foreach (var keyValue in resource)
{
dictionary[keyValue.Key] = new LocalizedString(keyValue.Key, keyValue.Value);
}
}
private Dictionary<string, string> GetResourceOrNull()
{
var resource = _applicationConfigurationClient
.Get()
.Localization.Values
.GetOrDefault(_resource.ResourceName);
if (resource == null)
{
_logger.LogWarning($"Could not find the localization resource {_resource.ResourceName} on the remote server!");
}
return resource;
}
}
}

33
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs

@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class RemoteSettingProvider : ISettingProvider, ITransientDependency
{
protected ICachedApplicationConfigurationClient ConfigurationClient { get; }
public RemoteSettingProvider(ICachedApplicationConfigurationClient configurationClient)
{
ConfigurationClient = configurationClient;
}
public async Task<string> GetOrNullAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return configuration.Setting.Values.GetOrDefault(name);
}
public async Task<List<SettingValue>> GetAllAsync()
{
var configuration = await ConfigurationClient.GetAsync();
return configuration
.Setting.Values
.Select(s => new SettingValue(s.Key, s.Value))
.ToList();
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs

@ -9,6 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
public ApplicationAuthConfigurationDto Auth { get; set; }
public ApplicationSettingConfigurationDto Setting { get; set; }
public CurrentUserDto CurrentUser { get; set; }
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationSettingConfigurationDto.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
[Serializable]
public class ApplicationSettingConfigurationDto
{
public Dictionary<string, string> Values { get; set; }
}
}

32
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
@ -20,27 +21,38 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
public string GetLocalizedText(string text, ModelExplorer explorer)
{
var localizer = GetStringLocalizer(explorer);
var resourceType = GetResourceTypeFromModelExplorer(explorer);
var localizer = GetStringLocalizer(resourceType);
return localizer == null ? text : localizer[text].Value;
}
public IStringLocalizer GetLocalizer(ModelExplorer explorer)
{
return GetStringLocalizer(explorer);
var resourceType = GetResourceTypeFromModelExplorer(explorer);
return GetStringLocalizer(resourceType);
}
private IStringLocalizer GetStringLocalizer(ModelExplorer explorer)
public IStringLocalizer GetLocalizer(Assembly assembly)
{
IStringLocalizer localizer = null;
var resourceType = _options.AssemblyResources.GetOrDefault(explorer.Container.ModelType.Assembly);
var resourceType = _options.AssemblyResources.GetOrDefault(assembly);
return GetStringLocalizer(resourceType);
}
if (resourceType != null)
{
localizer = _stringLocalizerFactory.Create(resourceType);
}
public IStringLocalizer GetLocalizer(Type resourceType)
{
return GetStringLocalizer(resourceType);
}
return localizer;
private IStringLocalizer GetStringLocalizer(Type resourceType)
{
return resourceType == null ? null : _stringLocalizerFactory.Create(resourceType);
}
private Type GetResourceTypeFromModelExplorer(ModelExplorer explorer)
{
var assembly = explorer.Container.ModelType.Assembly;
return _options.AssemblyResources.GetOrDefault(assembly);
}
}
}

88
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs

@ -56,93 +56,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
Process(context, output);
return Task.CompletedTask;
}
protected virtual TagHelperOutput GetInnerTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{
TagMode = tagMode
};
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync)
{
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));
}
else
{
tagHelper.Process(innerContext, innerOutput);
}
return innerOutput;
}
protected virtual string RenderTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = GetInnerTagHelper(attributeList, context, tagHelper, tagName, tagMode, runAsync);
return RenderTagHelperOutput(innerOutput, htmlEncoder);
}
protected virtual string RenderTagHelperOutput(TagHelperOutput output, HtmlEncoder htmlEncoder)
{
using (var writer = new StringWriter())
{
output.WriteTo(writer, htmlEncoder);
return writer.ToString();
}
}
protected virtual T GetAttribute<T>(ModelExplorer property) where T : Attribute
{
return property?.Metadata?.ContainerType?.GetTypeInfo()?.GetProperty(property.Metadata.PropertyName)?.GetCustomAttribute<T>();
}
protected virtual List<FormGroupItem> GetFormGroupContentsList(TagHelperContext context, out bool surpress)
{
var items = GetValueFromContext<List<FormGroupItem>>(context, FormGroupContents);
surpress = items != null;
return items ?? new List<FormGroupItem>();
}
protected virtual T GetValueFromContext<T>(TagHelperContext context, string key)
{
if (!context.Items.ContainsKey(key))
{
return default(T);
}
return (T)context.Items[key];
}
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual int GetInputOrder(ModelExplorer explorer)
{
return GetAttribute<DisplayOrder>(explorer)?.Number ?? DisplayOrder.Default;
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = GetFormGroupContentsList(context, out surpress);
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbItemTagHelperService.cs

@ -2,6 +2,7 @@
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
{
@ -20,13 +21,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
output.Attributes.AddClass("breadcrumb-item");
output.Attributes.AddClass(AbpBreadcrumbItemActivePlaceholder);
var list = GetValueFromContext<List<BreadcrumbItem>>(context, BreadcrumbItemsContent);
var list = context.GetValue<List<BreadcrumbItem>>(BreadcrumbItemsContent);
output.Content.SetHtmlContent(GetInnerHtml(context, output));
list.Add(new BreadcrumbItem
{
Html = RenderTagHelperOutput(output, _encoder),
Html = output.Render(_encoder),
Active = TagHelper.Active
});

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselItemTagHelperService.cs

@ -3,6 +3,7 @@ using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
{
@ -32,9 +33,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
private void AddToContext(TagHelperContext context, TagHelperOutput output)
{
var getOutputAsHtml = RenderTagHelperOutput(output, _encoder);
var getOutputAsHtml = output.Render(_encoder);
var itemList = GetValueFromContext<List<CarouselItem>>(context, CarouselItemsContent);
var itemList = context.GetValue<List<CarouselItem>>(CarouselItemsContent);
itemList.Add(new CarouselItem(getOutputAsHtml, TagHelper.Active ?? false));
}

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

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
@ -15,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
var html = GetAccordionHeaderItem(context, output) + GetAccordionContentItem(context, output, innerContent);
var tabHeaderItems = GetValueFromContext<List<string>>(context, AccordionItems);
var tabHeaderItems = context.GetValue<List<string>>(AccordionItems);
tabHeaderItems.Add(html);

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

@ -1,10 +1,12 @@
using System;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{
@ -22,22 +24,25 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
_serviceProvider = serviceProvider;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var buttonsAsHtml = GetButtonsAsHtml(context, output);
var content = await output.GetChildContentAsync();
var buttonsAsHtml = GetButtonsAsHtml(context, output, content);
output.PreElement.SetHtmlContent(buttonsAsHtml);
output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetContent("");
output.Attributes.Clear();
}
protected virtual string GetButtonsAsHtml(TagHelperContext context, TagHelperOutput output)
protected virtual string GetButtonsAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperContent content)
{
var buttonBuilder = new StringBuilder("");
var mainButton = GetMainButton(context, output);
var mainButton = GetMainButton(context, output, content);
buttonBuilder.AppendLine(mainButton);
@ -51,10 +56,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
return buttonBuilder.ToString();
}
protected virtual string GetMainButton(TagHelperContext context, TagHelperOutput output)
protected virtual string GetMainButton(TagHelperContext context, TagHelperOutput output, TagHelperContent content)
{
var abpButtonTagHelper = _serviceProvider.GetRequiredService<AbpButtonTagHelper>();
abpButtonTagHelper.Icon = TagHelper.Icon;
abpButtonTagHelper.Text = TagHelper.Text;
abpButtonTagHelper.IconType = TagHelper.IconType;
@ -62,15 +67,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForMainButton(context, output);
var buttonTag = GetInnerTagHelper(attributes, context, abpButtonTagHelper, "button", TagMode.StartTagAndEndTag);
var buttonTag = abpButtonTagHelper.ProcessAndGetOutput(attributes, context, "button", TagMode.StartTagAndEndTag);
buttonTag.PreContent.SetHtmlContent(content.GetContent());
if ((TagHelper.NavLink ?? false) || (TagHelper.Link ?? false))
{
var linkTag = ConvertButtonToLink(buttonTag);
return RenderTagHelperOutput(linkTag, _htmlEncoder);
return linkTag.Render(_htmlEncoder);
}
return RenderTagHelperOutput(buttonTag, _htmlEncoder);
return buttonTag.Render(_htmlEncoder);
}
protected virtual string GetSplitButton(TagHelperContext context, TagHelperOutput output)
@ -81,7 +88,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForSplitButton(context, output);
return RenderTagHelper(attributes, context, abpButtonTagHelper, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
return abpButtonTagHelper.Render(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
}
protected virtual TagHelperAttributeList GetAttributesForMainButton(TagHelperContext context, TagHelperOutput output)

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownTagHelperService.cs

@ -8,6 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.Attributes.AddClass("dropdown");
output.Attributes.AddClass("btn-group");
SetDirection(context, output);

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/ModelExplorerExtensions.cs

@ -0,0 +1,20 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class ModelExplorerExtensions
{
public static T GetAttribute<T>(this ModelExplorer property) where T : Attribute
{
return property?.Metadata?.ContainerType?.GetTypeInfo()?.GetProperty(property.Metadata.PropertyName)?.GetCustomAttribute<T>();
}
public static int GetDisplayOrder(this ModelExplorer explorer)
{
return GetAttribute<DisplayOrder>(explorer)?.Number ?? DisplayOrder.Default;
}
}
}

25
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperAttributeExtensions.cs

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperAttributeExtensions
{
public static string ToHtmlAttributeAsString(this TagHelperAttribute attribute)
{
return attribute.Name + "=\"" + attribute.Value + "\"";
}
public static string ToHtmlAttributesAsString(this List<TagHelperAttribute> attributes)
{
var attributesAsString = "";
foreach (var attribute in attributes)
{
attributesAsString += attribute.ToHtmlAttributeAsString() + " ";
}
return attributesAsString;
}
}
}

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperContextExtensions.cs

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperContextExtensions
{
public static T GetValue<T>(this TagHelperContext context, string key)
{
if (!context.Items.ContainsKey(key))
{
return default(T);
}
return (T)context.Items[key];
}
}
}

41
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs

@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text.Encodings.Web;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperExtensions
{
public static TagHelperOutput ProcessAndGetOutput(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{
TagMode = tagMode
};
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync)
{
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));
}
else
{
tagHelper.Process(innerContext, innerOutput);
}
return innerOutput;
}
public static string Render(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = tagHelper.ProcessAndGetOutput(attributeList, context, tagName, tagMode, runAsync);
return innerOutput.Render(htmlEncoder);
}
}
}

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperOutputExtensions.cs

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.IO;
using System.Text.Encodings.Web;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperOutputExtensions
{
public static string Render(this TagHelperOutput output, HtmlEncoder htmlEncoder)
{
using (var writer = new StringWriter())
{
output.WriteTo(writer, htmlEncoder);
return writer.ToString();
}
}
}
}

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

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
@ -66,7 +67,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
var formTagOutput = GetInnerTagHelper(output.Attributes, context, formTagHelper, "form", TagMode.StartTagAndEndTag);
var formTagOutput = formTagHelper.ProcessAndGetOutput(output.Attributes, context, "form", TagMode.StartTagAndEndTag);
await formTagOutput.GetChildContentAsync();
@ -146,7 +147,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var abpSelectTagHelper = GetSelectGroupTagHelper(context, output, model);
RenderTagHelper(new TagHelperAttributeList(), context, abpSelectTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
abpSelectTagHelper.Render(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
}
protected virtual AbpTagHelper GetSelectGroupTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@ -156,7 +157,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
GetSelectTagHelper(model);
}
private AbpTagHelper GetSelectTagHelper(ModelExpression model)
protected virtual AbpTagHelper GetSelectTagHelper(ModelExpression model)
{
var abpSelectTagHelper = _serviceProvider.GetRequiredService<AbpSelectTagHelper>();
abpSelectTagHelper.AspFor = model;
@ -165,9 +166,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return abpSelectTagHelper;
}
private AbpTagHelper GetAbpRadioInputTagHelper(ModelExpression model)
protected virtual AbpTagHelper GetAbpRadioInputTagHelper(ModelExpression model)
{
var radioButtonAttribute = GetAttribute<AbpRadioButton>(model.ModelExplorer);
var radioButtonAttribute = model.ModelExplorer.GetAttribute<AbpRadioButton>();
var abpRadioInputTagHelper = _serviceProvider.GetRequiredService<AbpRadioInputTagHelper>();
abpRadioInputTagHelper.AspFor = model;
abpRadioInputTagHelper.AspItems = null;
@ -184,7 +185,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpButtonTagHelper.Text = "Submit";
abpButtonTagHelper.ButtonType = AbpButtonType.Primary;
return RenderTagHelper(attributes, context, abpButtonTagHelper, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
return abpButtonTagHelper.Render(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
}
protected virtual void ProcessInputGroup(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@ -194,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpInputTagHelper.ViewContext = TagHelper.ViewContext;
abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true;
RenderTagHelper(new TagHelperAttributeList(), context, abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
abpInputTagHelper.Render(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
}
protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output)
@ -280,12 +281,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual bool AreSelectItemsProvided(ModelExplorer explorer)
{
return GetAttribute<SelectItems>(explorer) != null;
return explorer.GetAttribute<SelectItems>() != null;
}
protected virtual bool IsRadioGroup(ModelExplorer explorer)
{
return GetAttribute<AbpRadioButton>(explorer) != null;
return explorer.GetAttribute<AbpRadioButton>() != null;
}
}
}

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
public enum AbpFormControlSize
{

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

@ -6,10 +6,8 @@ using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
@ -30,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var innerHtml = GetFormInputGroupAsHtml(context, output, out var isCheckbox);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer);
var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
AddGroupToFormGroupContents(
context,
@ -49,7 +47,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.TagMode = TagMode.StartTagAndEndTag;
output.TagName = "div";
LeaveOnlyGroupAttributes(context, output);
output.Attributes.AddClass(isCheckbox ? "form-check" : "form-group");
output.Attributes.AddClass(isCheckbox ? "custom-checkbox" : "form-group");
output.Attributes.AddClass(isCheckbox ? "custom-control" : "");
output.Attributes.AddClass(isCheckbox ? "mb-2" : "");
output.Content.SetHtmlContent(output.Content.GetContent() + innerHtml);
}
@ -58,8 +57,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox)
{
var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox);
var inputHtml = RenderTagHelperOutput(inputTag, _encoder);
var inputHtml = inputTag.Render(_encoder);
var label = GetLabelAsHtml(context, output, inputTag, isCheckbox);
var info = GetInfoAsHtml(context, output, inputTag, isCheckbox);
var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag);
@ -82,7 +81,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
return validationMessageTagHelper.Render(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag, true);
}
protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox)
@ -96,14 +95,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox)
{
return "<div class=\"" + (isCheckbox ? "form-check" : "form-group") + "\">" +
return "<div class=\"" + (isCheckbox ? "custom-checkbox custom-control" : "form-group") + "\">" +
Environment.NewLine + innerHtml + Environment.NewLine +
"</div>";
}
protected virtual TagHelper GetInputTagHelper(TagHelperContext context, TagHelperOutput output)
{
var textAreaAttribute = GetAttribute<TextArea>(TagHelper.AspFor.ModelExplorer);
var textAreaAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<TextArea>();
if (textAreaAttribute != null)
{
@ -125,7 +124,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var tagHelper = GetInputTagHelper(context, output);
var inputTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, tagHelper, "input");
var inputTagHelperOutput = tagHelper.ProcessAndGetOutput(GetInputAttributes(context, output), context, "input");
ConvertToTextAreaIfTextArea(inputTagHelperOutput);
AddDisabledAttribute(inputTagHelperOutput);
@ -145,7 +144,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
if (isCheckbox)
{
className = "form-check-input";
className = "custom-control-input";
}
inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output));
@ -162,7 +161,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{
if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false &&
(TagHelper.IsDisabled || GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer) != null))
(TagHelper.IsDisabled || TagHelper.AspFor.ModelExplorer.GetAttribute<DisabledInput>() != null))
{
inputTagHelperOutput.Attributes.Add("disabled", "");
}
@ -171,7 +170,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput)
{
if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false &&
(TagHelper.IsReadonly != false || GetAttribute<ReadOnlyInput>(TagHelper.AspFor.ModelExplorer) != null))
(TagHelper.IsReadonly != false || TagHelper.AspFor.ModelExplorer.GetAttribute<ReadOnlyInput>() != null))
{
inputTagHelperOutput.Attributes.Add("readonly", "");
}
@ -184,7 +183,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return;
}
var attribute = GetAttribute<Placeholder>(TagHelper.AspFor.ModelExplorer);
var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<Placeholder>();
if (attribute != null)
{
@ -196,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{
if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null)
if (TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>() == null)
{
return;
}
@ -230,7 +229,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag);
}
var checkboxClass = isCheckbox ? "class=\"form-check-label\" " : "";
var checkboxClass = isCheckbox ? "class=\"custom-control-label\" " : "";
return "<label " + checkboxClass + GetIdAttributeAsString(inputTag) + ">"
+ TagHelper.Label +
@ -244,7 +243,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return "";
}
return GetAttribute<RequiredAttribute>(TagHelper.AspFor.ModelExplorer) != null ? "<span> * </span>":"";
return TagHelper.AspFor.ModelExplorer.GetAttribute<RequiredAttribute>() != null ? "<span> * </span>":"";
}
protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
@ -267,7 +266,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
}
else
{
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer);
var infoAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>();
if (infoAttribute != null)
{
text = infoAttribute.Text;
@ -298,15 +297,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
if (isCheckbox)
{
attributeList.AddClass("form-check-label");
attributeList.AddClass("custom-control-label");
}
return RenderTagHelper(attributeList, context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true);
return labelTagHelper.Render(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag, true);
}
protected virtual void ConvertToTextAreaIfTextArea(TagHelperOutput tagHelperOutput)
{
var textAreaAttribute = GetAttribute<TextArea>(TagHelper.AspFor.ModelExplorer);
var textAreaAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<TextArea>();
if (textAreaAttribute == null)
{
@ -358,7 +357,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer);
var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<FormControlSize>();
if (attribute != null)
{
@ -382,5 +381,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden");
}
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
}
}

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs

@ -1,5 +1,4 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

22
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs

@ -7,8 +7,7 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
@ -26,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var selectItems = GetSelectItems(context,output);
SetSelectedValue(context, output, selectItems);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer);
var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
var html = GetHtml(context, output, selectItems);
@ -80,7 +79,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
}
var selectItemsAttribute = GetAttribute<SelectItems>(TagHelper.AspFor.ModelExplorer);
var selectItemsAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<SelectItems>();
if (selectItemsAttribute != null)
{
return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
@ -157,5 +156,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return TagHelper.AspFor.ModelExplorer.Model?.ToString();
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
}
}

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

@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -10,9 +9,8 @@ using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
@ -33,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var innerHtml = GetFormInputGroupAsHtml(context, output);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer);
var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, SurroundInnerHtmlAndGet(context, output, innerHtml), order, out var surpress);
@ -54,7 +52,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output)
{
var selectTag = GetSelectTag(context, output);
var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder);
var selectAsHtml = selectTag.Render(_encoder);
var label = GetLabelAsHtml(context, output, selectTag);
var validation = GetValidationAsHtml(context, output, selectTag);
var infoText = GetInfoAsHtml(context, output, selectTag);
@ -76,7 +74,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
var selectTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, selectTagHelper, "select", TagMode.StartTagAndEndTag);
var selectTagHelperOutput = selectTagHelper.ProcessAndGetOutput(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag);
selectTagHelperOutput.Attributes.AddClass("form-control");
selectTagHelperOutput.Attributes.AddClass(GetSize(context, output));
@ -88,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{
var disabledAttribute = GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer);
var disabledAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<DisabledInput>();
if (disabledAttribute != null && !inputTagHelperOutput.Attributes.ContainsName("disabled"))
{
@ -108,7 +106,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
}
var selectItemsAttribute = GetAttribute<SelectItems>(TagHelper.AspFor.ModelExplorer);
var selectItemsAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<SelectItems>();
if (selectItemsAttribute != null)
{
return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
@ -135,12 +133,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return "";
}
return GetAttribute<RequiredAttribute>(TagHelper.AspFor.ModelExplorer) != null ? "<span> * </span>" : "";
return TagHelper.AspFor.ModelExplorer.GetAttribute<RequiredAttribute>() != null ? "<span> * </span>" : "";
}
protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{
if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null)
if (TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>() == null)
{
return;
}
@ -167,7 +165,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
}
else
{
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer);
var infoAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>();
if (infoAttribute != null)
{
text = infoAttribute.Text;
@ -230,7 +228,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true);
return labelTagHelper.Render(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag, true);
}
protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
@ -243,12 +241,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
return validationMessageTagHelper.Render(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag, true);
}
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer);
var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<FormControlSize>();
if (attribute != null)
{
@ -258,11 +256,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
switch (TagHelper.Size)
{
case AbpFormControlSize.Small:
return "form-control-sm";
return "custom-select-sm";
case AbpFormControlSize.Medium:
return "form-control-md";
return "custom-select-md";
case AbpFormControlSize.Large:
return "form-control-lg";
return "custom-select-lg";
}
return "";
@ -280,6 +278,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
attrList.Add(tagHelperAttribute);
}
attrList.AddClass("custom-select");
return attrList;
}
@ -297,5 +297,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.Add(newAttritube);
}
}
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
}
}

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{

44
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs

@ -10,23 +10,31 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.TagName = "div";
output.Attributes.AddClass("col");
ProcessSizeClass(output, TagHelper.Size, "");
ProcessSizeClass(output, TagHelper.SizeSm, "-sm");
ProcessSizeClass(output, TagHelper.SizeMd, "-md");
ProcessSizeClass(output, TagHelper.SizeLg, "-lg");
ProcessSizeClass(output, TagHelper.SizeXl, "-xl");
ProcessOffsetClass(output, TagHelper.Offset, "");
ProcessOffsetClass(output, TagHelper.OffsetSm, "-sm");
ProcessOffsetClass(output, TagHelper.OffsetMd, "-md");
ProcessOffsetClass(output, TagHelper.OffsetLg, "-lg");
ProcessOffsetClass(output, TagHelper.OffsetXl, "-xl");
ProcessColumnOrder(output);
ProcessVerticalAlign(output);
ProcessSizeClasses(context, output);
ProcessOffsetClasses(context, output);
ProcessColumnOrder(context, output);
ProcessVerticalAlign(context, output);
}
protected virtual void ProcessSizeClass(TagHelperOutput output, ColumnSize size, string breakpoint)
protected virtual void ProcessSizeClasses(TagHelperContext context, TagHelperOutput output)
{
ProcessSizeClass(context, output, TagHelper.Size, "");
ProcessSizeClass(context, output, TagHelper.SizeSm, "-sm");
ProcessSizeClass(context, output, TagHelper.SizeMd, "-md");
ProcessSizeClass(context, output, TagHelper.SizeLg, "-lg");
ProcessSizeClass(context, output, TagHelper.SizeXl, "-xl");
}
protected virtual void ProcessOffsetClasses(TagHelperContext context, TagHelperOutput output)
{
ProcessOffsetClass(context, output, TagHelper.Offset, "");
ProcessOffsetClass(context, output, TagHelper.OffsetSm, "-sm");
ProcessOffsetClass(context, output, TagHelper.OffsetMd, "-md");
ProcessOffsetClass(context, output, TagHelper.OffsetLg, "-lg");
ProcessOffsetClass(context, output, TagHelper.OffsetXl, "-xl");
}
protected virtual void ProcessSizeClass(TagHelperContext context, TagHelperOutput output, ColumnSize size, string breakpoint)
{
if (size == ColumnSize.Undefined)
{
@ -47,7 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass(classString);
}
protected virtual void ProcessOffsetClass(TagHelperOutput output, ColumnSize size, string breakpoint)
protected virtual void ProcessOffsetClass(TagHelperContext context, TagHelperOutput output, ColumnSize size, string breakpoint)
{
if (size == ColumnSize.Undefined)
{
@ -68,7 +76,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass(classString);
}
protected virtual void ProcessVerticalAlign(TagHelperOutput output)
protected virtual void ProcessVerticalAlign(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.VAlign == VerticalAlign.Default)
{
@ -78,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass("align-self-" + TagHelper.VAlign.ToString().ToLowerInvariant());
}
protected virtual void ProcessColumnOrder(TagHelperOutput output)
protected virtual void ProcessColumnOrder(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.ColumnOrder == ColumnOrder.Undefined)
{

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs

@ -1,5 +1,9 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{
[HtmlTargetElement("abp-row")]
[HtmlTargetElement("abp-form-row")]
public class AbpRowTagHelper : AbpTagHelper<AbpRowTagHelper, AbpRowTagHelperService>
{
public VerticalAlign VAlign { get; set; } = VerticalAlign.Default;

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs

@ -7,8 +7,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (output.TagName == "abp-row")
{
output.Attributes.AddClass("row");
}
if (output.TagName == "abp-form-row")
{
output.Attributes.AddClass("form-row");
}
output.TagName = "div";
output.Attributes.AddClass("row");
ProcessVerticalAlign(output);
ProcessHorizontalAlign(output);

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

@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
@ -9,5 +11,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
string GetLocalizedText(string text, ModelExplorer explorer);
IStringLocalizer GetLocalizer(ModelExplorer explorer);
IStringLocalizer GetLocalizer(Assembly assembly);
IStringLocalizer GetLocalizer(Type resourceType);
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelper.cs

@ -1,11 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Label
{
public class AbpLabelTagHelper : AbpTagHelper<AbpLabelTagHelper, AbpLabelTagHelperService>
{
public AbpLabelTagHelper(AbpLabelTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelperService.cs

@ -1,12 +0,0 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Label
{
public class AbpLabelTagHelperService : AbpTagHelperService<AbpLabelTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//TODO: fill
}
}
}

19
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
{
@ -13,13 +14,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
{
private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder;
private readonly IStringLocalizer<AbpUiResource> _localizer;
private readonly IAbpTagHelperLocalizer _tagHelperLocalizer;
public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IStringLocalizer<AbpUiResource> localizer)
public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer)
{
_generator = generator;
_encoder = encoder;
_localizer = localizer;
_tagHelperLocalizer = tagHelperLocalizer;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
@ -117,13 +118,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
protected virtual string RenderAnchorTagHelperLinkHtml(TagHelperContext context, TagHelperOutput output, string currentPage, string localizationKey)
{
var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource));
var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList);
var tagHelperOutput = GetInnerTagHelper(attributeList, context, anchorTagHelper, "a", TagMode.StartTagAndEndTag);
var tagHelperOutput = anchorTagHelper.ProcessAndGetOutput(attributeList, context, "a", TagMode.StartTagAndEndTag);
tagHelperOutput.Content.SetHtmlContent(_localizer[localizationKey]);
tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]);
var renderedHtml = RenderTagHelperOutput(tagHelperOutput, _encoder);
var renderedHtml = tagHelperOutput.Render(_encoder);
return renderedHtml;
}
@ -150,8 +153,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
protected virtual string GetOpeningTags(TagHelperContext context, TagHelperOutput output)
{
var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource));
var pagerInfo = (TagHelper.ShowInfo ?? false) ?
" <div class=\"col-sm-12 col-md-5\"> " + _localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "</div>\r\n"
" <div class=\"col-sm-12 col-md-5\"> " + localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "</div>\r\n"
: "";
return

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Popover/AbpPopoverTagHelperService.cs

@ -7,7 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Popover
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!TagHelper.Disabled??true)
if (!TagHelper.Disabled ?? true)
{
SetDataToggle(context, output);
SetDataPlacement(context, output);
@ -16,21 +16,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Popover
}
else
{
SetDisabled(context,output);
SetDisabled(context, output);
}
}
protected virtual void SetDisabled(TagHelperContext context, TagHelperOutput output)
{
var triggerAsHtml = TagHelper.Dismissible ?? false ? "datatrigger=\"focus\" " : "";
var dataPlacementAsHtml = "data-placement=\"" +GetDirectory().ToString().ToLowerInvariant() + "\" ";
var dataPlacementAsHtml = "data-placement=\"" + GetDirectory().ToString().ToLowerInvariant() + "\" ";
var titleAttribute = output.Attributes.FirstOrDefault(at => at.Name == "title");
var titleAsHtml = titleAttribute == null? "":"title=\""+ titleAttribute.Value +"\" ";
var preElementHtml = "<span class=\"d-inline-block\" "+ titleAsHtml + triggerAsHtml + dataPlacementAsHtml + "data-toggle=\"popover\" data-content=\"" +GetDataContent()+"\">";
var titleAsHtml = titleAttribute == null ? "" : "title=\"" + titleAttribute.Value + "\" ";
var preElementHtml = "<span class=\"d-inline-block\" " + titleAsHtml + triggerAsHtml + dataPlacementAsHtml + "data-toggle=\"popover\" data-content=\"" + GetDataContent() + "\">";
var postElementHtml = "</span>";
output.PreElement.SetHtmlContent(preElementHtml);

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs

@ -10,6 +10,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
output.Attributes.AddClass("progress");
output.TagName = "div";
}
}
}

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
@ -17,7 +18,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
await output.GetChildContentAsync();
var tabHeader = GetTabHeaderItem(context, output);
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems);
var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, "", true));

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
@ -12,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var tabHeader = GetTabHeaderItem(context, output);
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems);
var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, TagHelper.ParentDropdownName, false));

37
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
@ -12,9 +14,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var innerContent = await output.GetChildContentAsync();
var tabHeader = GetTabHeaderItem(context, output);
var tabContent = GetTabContentItem(innerContent.GetContent());
var tabContent = GetTabContentItem(context, output, innerContent.GetContent());
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems);
var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
var active = TagHelper.Active ?? false;
@ -29,23 +31,31 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var link = TagHelper.Name;
var control = TagHelper.Name;
var title = TagHelper.Title;
var attributes = GetTabHeaderAttributes(context, output);
var classAttributesAsString = attributes.Where(a=>a.Name == "class").ToList().Select(a=>a.Value).JoinAsString(" ");
var otherAttributesAsString = attributes.Where(a => a.Name != "class").ToList().ToHtmlAttributesAsString();
if (!string.IsNullOrWhiteSpace(TagHelper.ParentDropdownName))
{
return "<a class=\"dropdown-item\" id=\"" + id + "\" href=\"#" + link + "\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"false\">" + title + "</a>";
return "<a class=\"dropdown-item "+ classAttributesAsString + "\" id=\"" + id + "\" href=\"#" + link + "\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"false\" "+ otherAttributesAsString + ">" + title + "</a>";
}
return "<li class=\"nav-item\"><a class=\"nav-link" + AbpTabItemActivePlaceholder + "\" id=\"" + id + "\" data-toggle=\"" + TabItemsDataTogglePlaceHolder + "\" href=\"#" + link + "\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"" + AbpTabItemSelectedPlaceholder + "\">" +
return "<li class=\"nav-item\"><a class=\"nav-link " + classAttributesAsString + " " + AbpTabItemActivePlaceholder + "\" id=\"" + id + "\" data-toggle=\"" + TabItemsDataTogglePlaceHolder + "\" href=\"#" + link + "\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"" + AbpTabItemSelectedPlaceholder + "\" "+ otherAttributesAsString + ">" +
title +
"</a></li>";
}
protected virtual string GetTabContentItem(string content)
protected virtual string GetTabContentItem(TagHelperContext context, TagHelperOutput output, string content)
{
var headerId = TagHelper.Name + "-tab";
var id = TagHelper.Name;
var attributes = GetTabContentAttributes(context, output);
var classAttributesAsString = attributes.Where(a => a.Name == "class").ToList().Select(a => a.Name).JoinAsString(" ");
var otherAttributesAsString = attributes.Where(a => a.Name != "class").ToList().ToHtmlAttributesAsString();
return "<div class=\"tab-pane fade" + AbpTabItemShowActivePlaceholder + "\" id=\"" + id + "\" role=\"tabpanel\" aria-labelledby=\"" + headerId + "\">" +
return "<div class=\"tab-pane fade " + classAttributesAsString + " " + AbpTabItemShowActivePlaceholder + "\" id=\"" + id + "\" role=\"tabpanel\" aria-labelledby=\"" + headerId + "\" " + otherAttributesAsString + ">" +
content +
"</div>";
}
@ -57,5 +67,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
TagHelper.Name = TabItemNamePlaceHolder;
}
}
protected virtual List<TagHelperAttribute> GetTabContentAttributes(TagHelperContext context, TagHelperOutput output) {
var contentprefix = "content-";
return GetTabAttributesByPrefix(output.Attributes, contentprefix);
}
protected virtual List<TagHelperAttribute> GetTabHeaderAttributes(TagHelperContext context, TagHelperOutput output) {
var headerprefix = "header-";
return GetTabAttributesByPrefix(output.Attributes, headerprefix);
}
private List<TagHelperAttribute> GetTabAttributesByPrefix(TagHelperAttributeList attributes, string prefix) {
return attributes.Where(a=>a.Name.StartsWith(prefix))
.Select(a=> new TagHelperAttribute(a.Name.Substring(prefix.Length), a.Value)).ToList();
}
}
}

38
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollection.cs

@ -1,8 +1,8 @@
using System;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
@ -18,6 +18,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
public void Add(BundleContributor contributor)
{
foreach (var dependedType in GetDirectDependencies(contributor.GetType()))
{
AddWithDependencies(dependedType);
}
_contributors.Add(contributor);
}
@ -39,11 +44,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
return _contributors.ToImmutableList();
}
private bool IsAlreadyAdded(Type contributorType)
{
return _contributors.Any(c => c.GetType() == contributorType);
}
private void AddWithDependencies(Type contributorType)
{
if (IsAlreadyAdded(contributorType))
@ -51,20 +51,28 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
return;
}
foreach (var dependedType in GetDirectDependencies(contributorType))
{
AddWithDependencies(dependedType); //Recursive call
}
AddInstanceToContributors(contributorType);
}
private IEnumerable<Type> GetDirectDependencies(Type contributorType)
{
var dependsOnAttributes = contributorType
.GetCustomAttributes(true)
.OfType<IDependedTypesProvider>()
.ToList();
foreach (var dependsOnAttribute in dependsOnAttributes)
{
foreach (var dependedType in dependsOnAttribute.GetDependedTypes())
{
AddWithDependencies(dependedType); //Recursive call
}
}
return dependsOnAttributes
.SelectMany(a => a.GetDependedTypes());
}
AddInstanceToContributors(contributorType);
private bool IsAlreadyAdded(Type contributorType)
{
return _contributors.Any(c => c.GetType() == contributorType);
}
private void AddInstanceToContributors(Type contributorType)

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Components/TenantSwitch/Default.cshtml

@ -1,14 +1,17 @@
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Components.TenantSwitch
@model TenantSwitchViewComponent.TenantSwitchViewModel
<li class="nav-item">
<a abp-button="Link" id="TenantSwitchToolbarLink" href="#">
@if (Model.Tenant == null)
{
<text>@@host</text>
}
else
{
<text>@@@Model.Tenant.Name</text>
}
</a>
</li>
@if (!Model.CurrentUser.IsAuthenticated)
{
<li class="nav-item">
<a abp-button="Link" id="TenantSwitchToolbarLink" href="#">
@if (Model.Tenant == null)
{
<text>@@host</text>
}
else
{
<text>@@@Model.Tenant.Name</text>
}
</a>
</li>
}

16
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Components/TenantSwitch/TenantSwitchViewComponent.cs

@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Components.TenantSwitch
{
@ -12,18 +13,25 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Components.TenantSwitch
public const int Order = -1_000_000;
protected ITenantStore TenantStore { get; }
protected ICurrentTenant CurrentTenant { get; }
protected ICurrentUser CurrentUser { get; }
public TenantSwitchViewComponent(ITenantStore tenantStore, ICurrentTenant currentTenant)
public TenantSwitchViewComponent(
ITenantStore tenantStore,
ICurrentTenant currentTenant,
ICurrentUser currentUser)
{
TenantStore = tenantStore;
CurrentTenant = currentTenant;
CurrentUser = currentUser;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var model = new TenantSwitchViewModel();
var model = new TenantSwitchViewModel
{
CurrentUser = CurrentUser
};
if (CurrentTenant.Id.HasValue)
{
@ -36,6 +44,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Components.TenantSwitch
public class TenantSwitchViewModel
{
public TenantInfo Tenant { get; set; }
public ICurrentUser CurrentUser { get; set; }
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/AbpAspNetCoreMvcUIBasicThemeModule.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
@ -46,7 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
{
bundle
.AddBaseBundles(StandardBundles.Styles.Global)
.AddContributors(new BasicThemeGlobalStyleContributor());
.AddContributors(typeof(BasicThemeGlobalStyleContributor));
});
options

19
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js

@ -52,7 +52,7 @@
*************************************************************************/
var localize = function (key) {
return abp.localization.getResource('AbpUi')(key);
}
};
var recordActions = function () {
if (!$.fn.dataTableExt) {
@ -69,7 +69,7 @@
} else {
return visibilityField;
}
}
};
var _createDropdownItem = function (record, fieldItem) {
var $li = $('<li/>');
@ -83,7 +83,7 @@
$a.append($("<i>").addClass("fa fa-" + fieldItem.icon + " mr-1"));
} else if (fieldItem.iconClass) {
$a.append($("<i>").addClass(fieldItem.iconClass + " mr-1"));
}
}
$a.append(fieldItem.text);
}
@ -109,7 +109,7 @@
$a.appendTo($li);
return $li;
}
};
var _createButtonDropdown = function (record, field) {
var $container = $('<div/>')
@ -200,11 +200,11 @@
}
throw "DTE#1: Cannot create row action. Either set element or items fields!";
}
};
var hideColumnWithoutRedraw = function (tableInstance, colIndex) {
tableInstance.fnSetColumnVis(colIndex, false, false);
}
};
var hideEmptyColumn = function (cellContent, tableInstance, colIndex) {
if (cellContent == "") {
@ -307,8 +307,8 @@
});
});
}
}
}
};
};
}();
/************************************************************************
@ -338,9 +338,10 @@
}
}
configuration.dom = '<"dataTable_filters"f>rt<"row dataTable_footer"<"col-auto"l><"col-auto"i><"col"p>>';
return configuration;
}
};
}();

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/ContentLayout.cs

@ -1,4 +1,7 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Layout
using System;
using System.Linq;
namespace Volo.Abp.AspNetCore.Mvc.UI.Layout
{
public class ContentLayout
{
@ -12,5 +15,20 @@
{
BreadCrumb = new BreadCrumb();
}
public virtual bool ShouldShowBreadCrumb()
{
if (BreadCrumb.Items.Any())
{
return true;
}
if (BreadCrumb.ShowCurrent && !Title.IsNullOrEmpty())
{
return true;
}
return false;
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs

@ -60,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
public ICurrentTenant CurrentTenant { get; set; }
public ISettingManager SettingManager { get; set; }
public ISettingProvider SettingProvider { get; set; }
public IModelStateValidator ModelValidator { get; set; }

36
framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs

@ -0,0 +1,36 @@
using System;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Builder
{
public static class AbpAspNetCoreMvcApplicationBuilderExtensions
{
/// <summary>
/// Adds MVC to the <see cref="T:Microsoft.AspNetCore.Builder.IApplicationBuilder" /> request execution pipeline
/// with the following default routes:
///
/// - a default route named 'defaultWithArea' and the following template: '{area}/{controller=Home}/{action=Index}/{id?}'.
/// - a default route named 'default' and the following template: '{controller=Home}/{action=Index}/{id?}'.
/// </summary>
/// <param name="app">The <see cref="T:Microsoft.AspNetCore.Builder.IApplicationBuilder" />.</param>
/// <param name="additionalConfigurationAction">Additional action to configure routes</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseMvcWithDefaultRouteAndArea(
this IApplicationBuilder app,
Action<IRouteBuilder> additionalConfigurationAction = null)
{
return app.UseMvc(routes =>
{
routes.MapRoute(
name: "defaultWithArea",
template: "{area}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
additionalConfigurationAction?.Invoke(routes);
});
}
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -63,14 +63,6 @@ namespace Volo.Abp.AspNetCore.Mvc
options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter));
});
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(AbpAspNetCoreMvcModule).Assembly, o =>
{
o.RootPath = "abp";
});
});
var mvcCoreBuilder = context.Services.AddMvcCore();
context.Services.ExecutePreConfiguredActions(mvcCoreBuilder);

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

Loading…
Cancel
Save