Browse Source

Merge pull request #5 from abpframework/master

merge
pull/781/head
Marcelo Mohr Maciel 7 years ago
committed by GitHub
parent
commit
cd26fc0df4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      .gitignore
  2. 4
      README.md
  3. 2
      abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj
  4. 4
      abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj
  5. 826
      abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs
  6. 77
      abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs
  7. 58
      abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs
  8. 4
      abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj
  9. 90
      abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
  10. 40
      abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
  11. 3
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
  12. 1
      abp_io/src/Volo.AbpWebSite.Web/Startup.cs
  13. 8
      abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
  14. 2758
      abp_io/src/Volo.AbpWebSite.Web/package-lock.json
  15. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css
  16. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
  17. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss
  18. 4
      abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj
  19. 4
      build-all.ps1
  20. 23
      common.DotSettings
  21. 4
      common.props
  22. 138
      docs/en/AspNetCore/Auto-API-Controllers.md
  23. 75
      docs/en/AspNetCore/Bundling-Minification.md
  24. 165
      docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
  25. 84
      docs/en/Autofac-Integration.md
  26. 30
      docs/en/Best-Practices/MongoDB-Integration.md
  27. 86
      docs/en/Dependency-Injection.md
  28. 3
      docs/en/Dynamic-Proxying-Interceptors.md
  29. 2
      docs/en/Entities.md
  30. 38
      docs/en/Entity-Framework-Core.md
  31. 3
      docs/en/Event-Bus.md
  32. 20
      docs/en/Getting-Started-AspNetCore-Application.md
  33. 2
      docs/en/Getting-Started-AspNetCore-MVC-Template.md
  34. 75
      docs/en/Getting-Started-Console-Application.md
  35. 90
      docs/en/Index.md
  36. 29
      docs/en/Localization.md
  37. 30
      docs/en/Microservice-Architecture.md
  38. 33
      docs/en/Module-Development-Basics.md
  39. 475
      docs/en/Modules/Docs.md
  40. 26
      docs/en/Modules/Index.md
  41. 77
      docs/en/MongoDB.md
  42. 40
      docs/en/Samples/Microservice-Demo.md
  43. 12
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  44. 6
      docs/en/Virtual-File-System.md
  45. 34
      docs/en/docs-nav.json
  46. BIN
      docs/en/images/bookstore-apis.png
  47. BIN
      docs/en/images/docs-module_download-new-abp-project.png
  48. BIN
      docs/en/images/docs-module_download-sample-navigation-menu.png
  49. BIN
      docs/en/images/docs-module_solution-explorer.png
  50. BIN
      docs/en/images/microservice-sample-diagram.png
  51. 138
      docs/zh-Hans/AspNetCore/Auto-API-Controllers.md
  52. 165
      docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md
  53. 84
      docs/zh-Hans/Autofac-Integration.md
  54. 3
      docs/zh-Hans/Event-Bus.md
  55. 30
      docs/zh-Hans/Microservice-Architecture.md
  56. 7
      docs/zh-Hans/Module-Development-Basics.md
  57. 467
      docs/zh-Hans/Modules/Docs.md
  58. 26
      docs/zh-Hans/Modules/Index.md
  59. 40
      docs/zh-Hans/Samples/Microservice-Demo.md
  60. 2
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
  61. 6
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
  62. 6
      docs/zh-Hans/Virtual-File-System.md
  63. 43
      docs/zh-Hans/docs-nav.json
  64. BIN
      docs/zh-Hans/images/bookstore-apis.png
  65. BIN
      docs/zh-Hans/images/docs-module_download-new-abp-project.png
  66. BIN
      docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png
  67. BIN
      docs/zh-Hans/images/docs-module_solution-explorer.png
  68. BIN
      docs/zh-Hans/images/microservice-sample-diagram.png
  69. 46
      framework/Volo.Abp.sln
  70. 8
      framework/Volo.Abp.sln.DotSettings
  71. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
  72. 8
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs
  73. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs
  74. 4
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs
  75. 4
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs
  76. 4
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs
  77. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs
  78. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs
  79. 4
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs
  80. 22
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  81. 26
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
  82. 65
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
  83. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs
  84. 32
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs
  85. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj
  86. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs
  87. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs
  88. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
  89. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
  90. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs
  91. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs
  92. 58
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs
  93. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
  94. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs
  95. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs
  96. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs
  97. 15
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs
  98. 55
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs
  99. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs
  100. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs

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

4
README.md

@ -1,6 +1,6 @@
# ABP
[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://vjenkins.dynu.net:5480/blue/organizations/jenkins/abp/activity)
[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity)
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://abp.io/blog/abp/Abp-vNext-Announcement).
@ -22,7 +22,7 @@ See the <a href="https://abp.io/documents/" target="_blank">documentation</a>.
#### Pre Requirements
- Visual Studio 2017 15.7.0+
- Visual Studio 2017 15.9.0+
#### Framework

2
abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace />
</PropertyGroup>

4
abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace />
</PropertyGroup>
@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Ionic.Zip" Version="1.9.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
</ItemGroup>

826
abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs

@ -0,0 +1,826 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.AbpWebSite.EntityFrameworkCore;
namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
{
[DbContext(typeof(AbpWebSiteDbContext))]
[Migration("20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties")]
partial class Added_ConcurrencyStamp_IsDeleted_ExtraProperties
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
b.Property<string>("Description")
.HasMaxLength(256);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsStatic");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("Regex")
.HasMaxLength(512);
b.Property<string>("RegexDescription")
.HasMaxLength(128);
b.Property<bool>("Required");
b.Property<int>("ValueType");
b.HasKey("Id");
b.ToTable("AbpClaimTypes");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDefault")
.HasColumnName("IsDefault");
b.Property<bool>("IsPublic")
.HasColumnName("IsPublic");
b.Property<bool>("IsStatic")
.HasColumnName("IsStatic");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.IsRequired()
.HasMaxLength(256);
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("NormalizedName");
b.ToTable("AbpRoles");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("ClaimValue")
.HasMaxLength(1024);
b.Property<Guid>("RoleId");
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AbpRoleClaims");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount")
.ValueGeneratedOnAdd()
.HasColumnName("AccessFailedCount")
.HasDefaultValue(0);
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("Email")
.HasColumnName("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("EmailConfirmed")
.HasDefaultValue(false);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<bool>("LockoutEnabled")
.ValueGeneratedOnAdd()
.HasColumnName("LockoutEnabled")
.HasDefaultValue(false);
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("Name")
.HasColumnName("Name")
.HasMaxLength(64);
b.Property<string>("NormalizedEmail")
.HasColumnName("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.IsRequired()
.HasColumnName("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash")
.HasColumnName("PasswordHash")
.HasMaxLength(256);
b.Property<string>("PhoneNumber")
.HasColumnName("PhoneNumber")
.HasMaxLength(16);
b.Property<bool>("PhoneNumberConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("PhoneNumberConfirmed")
.HasDefaultValue(false);
b.Property<string>("SecurityStamp")
.IsRequired()
.HasColumnName("SecurityStamp")
.HasMaxLength(256);
b.Property<string>("Surname")
.HasColumnName("Surname")
.HasMaxLength(64);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId");
b.Property<bool>("TwoFactorEnabled")
.ValueGeneratedOnAdd()
.HasColumnName("TwoFactorEnabled")
.HasDefaultValue(false);
b.Property<string>("UserName")
.IsRequired()
.HasColumnName("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("Email");
b.HasIndex("NormalizedEmail");
b.HasIndex("NormalizedUserName");
b.HasIndex("UserName");
b.ToTable("AbpUsers");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("ClaimValue")
.HasMaxLength(1024);
b.Property<Guid?>("TenantId");
b.Property<Guid>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AbpUserClaims");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.Property<Guid>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(64);
b.Property<string>("ProviderDisplayName")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.IsRequired()
.HasMaxLength(196);
b.Property<Guid?>("TenantId");
b.HasKey("UserId", "LoginProvider");
b.HasIndex("LoginProvider", "ProviderKey");
b.ToTable("AbpUserLogins");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
{
b.Property<Guid>("UserId");
b.Property<Guid>("RoleId");
b.Property<Guid?>("TenantId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId", "UserId");
b.ToTable("AbpUserRoles");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
{
b.Property<Guid>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(64);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<Guid?>("TenantId");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AbpUserTokens");
});
modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.IsRequired()
.HasMaxLength(64);
b.Property<string>("ProviderName")
.IsRequired()
.HasMaxLength(64);
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("Name", "ProviderName", "ProviderKey");
b.ToTable("AbpPermissionGrants");
});
modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(64);
b.Property<string>("ProviderName")
.HasMaxLength(64);
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2048);
b.HasKey("Id");
b.HasIndex("Name", "ProviderName", "ProviderKey");
b.ToTable("AbpSettings");
});
modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnName("Description")
.HasMaxLength(1024);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasColumnName("Name")
.HasMaxLength(256);
b.Property<string>("ShortName")
.IsRequired()
.HasColumnName("ShortName")
.HasMaxLength(32);
b.HasKey("Id");
b.ToTable("BlgBlogs");
});
modelBuilder.Entity("Volo.Blogging.Comments.Comment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<Guid>("PostId")
.HasColumnName("PostId");
b.Property<Guid?>("RepliedCommentId")
.HasColumnName("RepliedCommentId");
b.Property<string>("Text")
.IsRequired()
.HasColumnName("Text")
.HasMaxLength(1024);
b.HasKey("Id");
b.HasIndex("PostId");
b.HasIndex("RepliedCommentId");
b.ToTable("BlgComments");
});
modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<Guid>("BlogId")
.HasColumnName("BlogId");
b.Property<string>("ConcurrencyStamp");
b.Property<string>("Content")
.HasColumnName("Content")
.HasMaxLength(1048576);
b.Property<string>("CoverImage")
.IsRequired()
.HasColumnName("CoverImage");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<int>("ReadCount");
b.Property<string>("Title")
.IsRequired()
.HasColumnName("Title")
.HasMaxLength(512);
b.Property<string>("Url")
.IsRequired()
.HasColumnName("Url")
.HasMaxLength(64);
b.HasKey("Id");
b.HasIndex("BlogId");
b.ToTable("BlgPosts");
});
modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b =>
{
b.Property<Guid>("PostId")
.HasColumnName("PostId");
b.Property<Guid>("TagId")
.HasColumnName("TagId");
b.Property<DateTime>("CreationTime");
b.Property<Guid?>("CreatorId");
b.HasKey("PostId", "TagId");
b.HasIndex("TagId");
b.ToTable("BlgPostTags");
});
modelBuilder.Entity("Volo.Blogging.Tagging.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<Guid>("BlogId");
b.Property<string>("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnName("Description")
.HasMaxLength(512);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasColumnName("Name")
.HasMaxLength(64);
b.Property<int>("UsageCount")
.HasColumnName("UsageCount");
b.HasKey("Id");
b.ToTable("BlgTags");
});
modelBuilder.Entity("Volo.Blogging.Users.BlogUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<string>("Email")
.HasColumnName("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("EmailConfirmed")
.HasDefaultValue(false);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<string>("Name")
.HasColumnName("Name")
.HasMaxLength(64);
b.Property<string>("PhoneNumber")
.HasColumnName("PhoneNumber")
.HasMaxLength(16);
b.Property<bool>("PhoneNumberConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("PhoneNumberConfirmed")
.HasDefaultValue(false);
b.Property<string>("Surname")
.HasColumnName("Surname")
.HasMaxLength(64);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId");
b.Property<string>("UserName")
.IsRequired()
.HasColumnName("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.ToTable("BlgUsers");
});
modelBuilder.Entity("Volo.Docs.Projects.Project", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<string>("DefaultDocumentName")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("DocumentStoreType");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<string>("Format");
b.Property<string>("LatestVersionBranchName")
.HasMaxLength(128);
b.Property<string>("MainWebsiteUrl");
b.Property<string>("MinimumVersion");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("NavigationDocumentName")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("ShortName")
.IsRequired()
.HasMaxLength(32);
b.HasKey("Id");
b.ToTable("DocsProjects");
});
modelBuilder.Entity("Volo.Utils.SolutionTemplating.DownloadInfo", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<int>("CreationDuration");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<byte>("DatabaseProvider");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<string>("ProjectName")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("TemplateName")
.IsRequired()
.HasMaxLength(42);
b.Property<string>("Version")
.IsRequired()
.HasMaxLength(20);
b.HasKey("Id");
b.ToTable("Downloads");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityRole")
.WithMany("Claims")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Claims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Logins")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Roles")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Tokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Blogging.Comments.Comment", b =>
{
b.HasOne("Volo.Blogging.Posts.Post")
.WithMany()
.HasForeignKey("PostId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Volo.Blogging.Comments.Comment")
.WithMany()
.HasForeignKey("RepliedCommentId");
});
modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
{
b.HasOne("Volo.Blogging.Blogs.Blog")
.WithMany()
.HasForeignKey("BlogId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b =>
{
b.HasOne("Volo.Blogging.Posts.Post")
.WithMany("Tags")
.HasForeignKey("PostId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Volo.Blogging.Tagging.Tag")
.WithMany()
.HasForeignKey("TagId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

77
abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs

@ -0,0 +1,77 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
{
public partial class Added_ConcurrencyStamp_IsDeleted_ExtraProperties : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<bool>(
name: "IsDeleted",
table: "AbpUsers",
nullable: false,
defaultValue: false,
oldClrType: typeof(bool));
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpUsers",
nullable: true,
oldClrType: typeof(string),
oldMaxLength: 256);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpRoles",
maxLength: 256,
nullable: false,
oldClrType: typeof(string),
oldNullable: true);
migrationBuilder.AddColumn<string>(
name: "ConcurrencyStamp",
table: "AbpClaimTypes",
maxLength: 256,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "ExtraProperties",
table: "AbpClaimTypes",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ConcurrencyStamp",
table: "AbpClaimTypes");
migrationBuilder.DropColumn(
name: "ExtraProperties",
table: "AbpClaimTypes");
migrationBuilder.AlterColumn<bool>(
name: "IsDeleted",
table: "AbpUsers",
nullable: false,
oldClrType: typeof(bool),
oldDefaultValue: false);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpUsers",
maxLength: 256,
nullable: false,
oldClrType: typeof(string),
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpRoles",
nullable: true,
oldClrType: typeof(string),
oldMaxLength: 256);
}
}
}

58
abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs

@ -15,7 +15,7 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846")
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
@ -24,9 +24,18 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
b.Property<string>("Description")
.HasMaxLength(256);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsStatic");
b.Property<string>("Name")
@ -53,7 +62,11 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
@ -118,17 +131,20 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
.HasDefaultValue(0);
b.Property<string>("ConcurrencyStamp")
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("Email")
.HasColumnName("Email")
@ -142,11 +158,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime");
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<bool>("LockoutEnabled")
.ValueGeneratedOnAdd()
@ -641,7 +662,9 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<string>("DefaultDocumentName")
.IsRequired()
@ -685,13 +708,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp");
b.Property<int>("CreationDuration");
b.Property<DateTime>("CreationTime");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<byte>("DatabaseProvider");

4
abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace />
</PropertyGroup>
@ -11,7 +11,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.0" />
</ItemGroup>
<ItemGroup>

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

@ -1,22 +1,20 @@
using System.Globalization;
using System.IO;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Configuration;
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;
@ -24,9 +22,10 @@ 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.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using Volo.AbpWebSite.Bundling;
using Volo.Blogging;
@ -44,30 +43,33 @@ namespace Volo.AbpWebSite
typeof(AbpAccountWebModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpIdentityWebModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(BloggingApplicationModule),
typeof(BloggingWebModule)
)]
public class AbpWebSiteWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpAspNetCoreConfigurationOptions>(options =>
{
options.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly;
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
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);
}
private static void ConfigureLanguages(IServiceCollection services)
{
services.Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("en-US", "en-US", "English"));
});
}
private static void ConfigureBundles(IServiceCollection services)
{
services.Configure<BundlingOptions>(options =>
@ -112,14 +114,14 @@ namespace Volo.AbpWebSite
{
services.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)));
});
}
}
@ -138,12 +140,7 @@ namespace Volo.AbpWebSite
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
app.UseRequestLocalization(options =>
{
options.DefaultRequestCulture = new RequestCulture("en-US", "en-US");
options.AddSupportedCultures("en-US");
options.AddSupportedUICultures("en-US");
});
app.UseAbpRequestLocalization();
if (env.IsDevelopment())
{
@ -165,29 +162,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())
);
});
}
}
}
}

40
abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml

@ -195,34 +195,34 @@
</p>
</div>
<div class="row justify-content-md-center">
<div class="col-md">
<div class="col-lg">
<div class="code-block">
<pre class="line-numbers">
<code class="language-html">
&lt;abp-card&gt;
&lt;img abp-card-image="Top" src="~/images/my-dog.png" /&gt;
&lt;abp-card-body&gt;
&lt;abp-card-title&gt;Card title&lt;/abp-card-title&gt;
&lt;abp-card-text&gt;
&lt;p&gt;
This is a sample card component built by ABP bootstrap
card tag helper. ABP has tag helper wrappers for most of
the bootstrap components.
&lt;/p&gt;
&lt;/abp-card-text&gt;
&lt;a abp-button="Primary" href="#"&gt;Go somewhere &amp;rarr;&lt;/a&gt;
&lt;/abp-card-body&gt;
&lt;/abp-card&gt;
&lt;abp-card&gt;
&lt;img abp-card-image="Top" src="~/images/my-dog.png" /&gt;
&lt;abp-card-body&gt;
&lt;abp-card-title&gt;Card title&lt;/abp-card-title&gt;
&lt;abp-card-text&gt;
&lt;p&gt;
This is a sample card component built by ABP bootstrap
card tag helper. ABP has tag helper wrappers for most of
the bootstrap components.
&lt;/p&gt;
&lt;/abp-card-text&gt;
&lt;a abp-button="Primary" href="#"&gt;Go somewhere &amp;rarr;&lt;/a&gt;
&lt;/abp-card-body&gt;
&lt;/abp-card&gt;
</code>
</pre>
</div>
</div>
<div class="col-md-1">
<div class="col-lg-1">
<span class="code-arrow">
<i class="fa fa-long-arrow-right"></i>
</span>
</div>
<div class="col-md text-dark">
<div class="col-lg text-dark">
<div class="abp-browser">
<div class="browser-container">
<div class="browser-row">
@ -265,7 +265,7 @@
</div>
<div class="row justify-content-md-center">
<div class="col-md">
<div class="col-lg">
<div class="code-block">
<pre class="line-numbers" data-line="">
<code class="language-xml">
@ -300,12 +300,12 @@ public class PersonModel
</pre>
</div>
</div>
<div class="col-md-1">
<div class="col-lg-1">
<span class="code-arrow">
<i class="fa fa-long-arrow-right"></i>
</span>
</div>
<div class="col-md">
<div class="col-lg">
<div class="abp-browser">
<div class="browser-container">
<div class="browser-row">

3
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml

@ -26,8 +26,7 @@
<a class="nav-link" href="https://github.com/abpframework/abp/" target="_blank">Github</a>
</li>
<li class="for-mobile">
<button type="button" class="close close-mmenu" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="close close-mmenu" aria-label="Close">
</button>
</li>
</ul>

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

@ -15,6 +15,7 @@ namespace Volo.AbpWebSite
services.AddApplication<AbpWebSiteWebModule>(options =>
{
options.UseAutofac();
options.Configuration.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly;
});
return services.BuildServiceProviderFromFactory();

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

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>Volo.AbpWebSite</RootNamespace>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
@ -14,7 +14,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
@ -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" />

2758
abp_io/src/Volo.AbpWebSite.Web/package-lock.json

File diff suppressed because it is too large

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css

@ -600,7 +600,7 @@ span.code-arrow {
.docs-page .docs-page-index {
display: none; } }
@media (max-width: 767px) {
@media (max-width: 992px) {
body {
font-size: 14px; }
.for-mobile {

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css

File diff suppressed because one or more lines are too long

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss

@ -3,7 +3,7 @@
@import "footer.scss";
@import "home.scss";
@import "docs.scss";
@media (max-width: 767px) {
@media (max-width: 992px) {
@import "responsive.scss";
}

4
abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj

@ -15,9 +15,9 @@
<ItemGroup>
<PackageReference Include="Ionic.Zip" Version="1.9.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />
</ItemGroup>

4
build-all.ps1

@ -20,7 +20,8 @@ $solutionPaths = (
"abp_io",
"templates/module",
"templates/service",
"templates/mvc"
"templates/mvc",
"samples/MicroserviceDemo"
)
# Build all solutions
@ -31,6 +32,7 @@ foreach ($solutionPath in $solutionPaths) {
dotnet build
if (-Not $?) {
Write-Host ("Build failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}

23
common.DotSettings

@ -0,0 +1,23 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceIfStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceLockStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String>
</wpf:ResourceDictionary>

4
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.9.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>
@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.1" PrivateAssets="All" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" />
</ItemGroup>
</Project>

138
docs/en/AspNetCore/Auto-API-Controllers.md

@ -0,0 +1,138 @@
# Auto API Controllers
Once you create an [application service](Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
ABP can **automagically** configures your application services as MVC API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible fully customize it.
## Configuration
Basic configuration is simple. Just configure `AbpAspNetCoreMvcOptions` and use `ConventionalControllers.Create` method as shown below:
````csharp
[DependsOn(BookStoreApplicationModule)]
public class BookStoreWebModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
});
}
}
````
This example code configures all the application services in the assembly containing the class `BookStoreApplicationModule`. The figure below shows the resulting API on the [Swagger UI](https://swagger.io/tools/swagger-ui/).
![bookstore-apis](../images/bookstore-apis.png)
### Examples
Some example method names and the corresponding routes calculated by convention:
| Service Method Name | HTTP Method | Route |
| ----------------------------------------------------- | ----------- | -------------------------- |
| GetAsync(Guid id) | GET | /api/app/book/{id} |
| GetListAsync() | GET | /api/app/book |
| CreateAsync(CreateBookDto input) | POST | /api/app/book |
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} |
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} |
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors |
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor |
### HTTP Method
ABP uses a naming convention while determining the HTTP method for a service method (action):
- **Get**: Used if the method name starts with 'GetList', 'GetAll' or 'Get'.
- **Put**: Used if the method name starts with 'Put' or 'Update'.
- **Delete**: Used if the method name starts with 'Delete' or 'Remove'.
- **Post**: Used if the method name starts with 'Create', 'Add', 'Insert' or 'Post'.
- **Patch**: Used if the method name starts with 'Patch'.
- Otherwise, **Post** is used **by default**.
If you need to customize HTTP method for a particular method, then you can use one of the standard ASP.NET Core attributes ([HttpPost], [HttpGet], [HttpPut]... etc.). This requires to add [Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core) nuget package to your project that contains the service.
### Route
Route is calculated based on some conventions:
* It always starts with '**/api**'.
* Continues with a **route path**. Default value is '**/app**' and can be configured as like below:
````csharp
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.RootPath = "volosoft/book-store";
});
});
````
Then the route for getting a book will be '**/api/volosoft/book-store/book/{id}**'. This sample uses two-level root path, but you generally use a single level depth.
* Continues with the **normalized controller/service name**. Normalization removes 'AppService', 'ApplicationService' and 'Service' postfixes and converts it to **camelCase**. If your application service class name is 'BookAppService' then it becomes only '/book'.
* If you want to customize naming, then set the `UrlControllerNameNormalizer` option. It's a func delegate which allows you to determine the name per controller/service.
* If the method has an '**id**' parameter then it adds '**/{id}**' ro the route.
* Then it adds the action name if necessary. Action name is obtained from the method name on the service and normalized by;
* Removing '**Async**' postfix. If the method name is 'GetPhonesAsync' then it becomes 'GetPhones'.
* Removing **HTTP method prefix**. 'GetList', 'GetAll', 'Get', 'Put', 'Update', 'Delete', 'Remove', 'Create', 'Add', 'Insert', 'Post' and 'Patch' prefixes are removed based on the selected HTTP method. So, 'GetPhones' becomes 'Phones' since 'Get' prefix is a duplicate for a GET request.
* Converting the result to **camelCase**.
* If the resulting action name is **empty** then it's not added to the route. If it's not empty, it's added to the route (like '/phones'). For 'GetAllAsync' method name it will be empty, for 'GetPhonesAsync' method name is will be 'phones'.
* Normalization can be customized by setting the `UrlActionNameNormalizer` option. It's an action delegate that is called for every method.
* If there is another parameter with 'Id' postfix, then it's also added to the route as the final route segment (like '/phoneId').
## Service Selection
Creating conventional HTTP API controllers are not unique to application services actually.
### IRemoteService Interface
If a class implements the `IRemoteService` interface then it's automatically selected to be a conventional API controller. Since application services inherently implement it, they are considered as natural API controllers.
### RemoteService Attribute
`RemoteService` attribute can be used to mark a class as a remote service or disable for a particular class that inherently implements the `IRemoteService` interface. Example:
````csharp
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)]
public class PersonAppService : ApplicationService
{
}
````
### TypePredicate Option
You can further filter classes to become an API controller by providing the `TypePedicate` option:
````csharp
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.TypePredicate = type => { return true; };
});
});
````
Instead of returning `true` for every type, you can check it and return `false` if you don't want to expose this type as an API controller.
## API Explorer
API Exploring a service that makes possible to investigate API structure by the clients. Swagger uses it to create a documentation and test UI for an endpoint.
API Explorer is automatically enabled for conventional HTTP API controllers by default. Use `RemoteService` attribute to control it per class or method level. Example:
````csharp
[RemoteService(IsMetadataEnabled = false)]
public class PersonAppService : ApplicationService
{
}
````
Disabled `IsMetadataEnabled` which hides this service from API explorer and it will not be discoverable. However, it still can be usable for the clients know the exact API path/route.

75
docs/en/AspNetCore/Bundling-Minification.md

@ -1,5 +1,5 @@
## ASP.NET Core MVC Bundling & Minification
# ASP.NET Core MVC Bundling & Minification
There are many ways of bundling & minification of client side resources (JavaScript and CSS files). Most common ways are:
@ -8,7 +8,7 @@ There are many ways of bundling & minification of client side resources (JavaScr
ABP offers a simple, dynamic, powerful, modular and built-in way.
### Volo.Abp.AspNetCore.Mvc.UI.Bundling Package
## Volo.Abp.AspNetCore.Mvc.UI.Bundling Package
> This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually.
@ -34,7 +34,7 @@ namespace MyCompany.MyProject
}
````
### Razor Bundling Tag Helpers
## Razor Bundling Tag Helpers
The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-style-bundle` tag helpers. Example:
@ -54,7 +54,7 @@ This bundle defines a style bundle with a **unique name**: `MyGlobalBundle`. It'
* The bundle files may be **physical** files or [**virtual/embedded** files](../Virtual-File-System.md).
* ABP automatically adds **version query string** to the bundle file URL to prevent browsers from caching when the bundle is being updated. (like ?_v=67872834243042 - generated from last change date of the related files). The versioning works even if the bundle files are individually added to the page (on the development environment).
#### Importing The Bundling Tag Helpers
### Importing The Bundling Tag Helpers
> This is already imported by default with the startup templates. So, most of the time, you don't need to add it manually.
@ -64,7 +64,7 @@ In order to use bundle tag helpers, you need to add it into your `_ViewImports.c
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
````
#### Unnamed Bundles
### Unnamed Bundles
The `name` is **optional** for the razor bundle tag helpers. If you don't define a name, it's automatically **calculated** based on the used bundle file names (they are **concatenated** and **hashed**). Example:
@ -90,7 +90,7 @@ Advantages of **named** bundles:
* Other **modules can contribute** to the bundle by its name (see the sections below).
#### Single File
### Single File
If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a wrapping in the `abp-script-bundle` or `abp-style-bundle` tag. Example:
@ -100,11 +100,11 @@ If you need to just add a single file to the page, you can use the `abp-script`
The bundle name will be *scripts.my-scripts* for the example above ("/" is replaced by "."). All bundling features are work as expected for single file bundles too.
### Bundling Options
## Bundling Options
If you need to use same bundle in **multiple pages** or want to use some more **powerful features**, you can configure bundles **by code** in your [module](../Module-Development-Basics.md) class.
#### Creating A New Bundle
### Creating A New Bundle
Example usage:
@ -141,10 +141,9 @@ After defining such a bundle, it can be included into a page using the same tag
This time, no file defined in the tag helper definition because the bundle files are defined by the code.
#### Configuring An Existing Bundle
### Configuring An Existing Bundle
ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module.
Example:
ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module. Example:
````C#
[DependsOn(typeof(MyWebModule))]
@ -168,7 +167,7 @@ public class MyWebExtensionModule : AbpModule
> It's not possible to configure unnamed bundle tag helpers by code, because their name are not known at the development time. It's suggested to always use a name for a bundle tag helper.
### Bundle Contributors
## Bundle Contributors
Adding files to an existing bundle seems useful. What if you need to **replace** a file in the bundle or you want to **conditionally** add files? Defining a bundle contributor provides extra power for such cases.
@ -187,7 +186,7 @@ public class MyExtensionGlobalStyleContributor : BundleContributor
}
````
Then you can use this contributor as below:
Then you can use this contributor as like below:
````C#
services.Configure<BundlingOptions>(options =>
@ -200,8 +199,9 @@ services.Configure<BundlingOptions>(options =>
});
````
Contributors can also be used in the bundle tag helpers.
Example:
> You can also add contributors while creating a new bundle.
Contributors can also be used in the bundle tag helpers. Example:
````xml
<abp-style-bundle>
@ -213,7 +213,7 @@ Example:
`abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, its dependencies are also automatically added to the bundle.
#### Contributor Dependencies
### Contributor Dependencies
A bundle contributor can have one or more dependencies to other contributors.
Example:
@ -230,11 +230,40 @@ When a bundle contributor is added, its dependencies are **automatically and rec
Creating contributors and defining dependencies is a way of organizing bundle creation across different modules.
#### Accessing to the IServiceProvider
### Contributor Extensions
In some advanced scenarios, you may want to do some additional configuration whenever a bundle contributor is used. Contributor extensions works seamlessly when the extended contributor is used.
The example below adds some styles for prism.js library:
````csharp
public class MyPrismjsStyleExtension : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css");
}
}
````
Then you can configure `BundleContributorOptions` to extend existing `PrismjsStyleBundleContributor`.
````csharp
Configure<BundleContributorOptions>(options =>
{
options
.Extensions<PrismjsStyleBundleContributor>()
.Add<MyPrismjsStyleExtension>();
});
````
Whenever `PrismjsStyleBundleContributor` is added into a bundle, `MyPrismjsStyleExtension` will also be automatically added.
### Accessing to the IServiceProvider
While it is rarely needed, `BundleConfigurationContext` has a `ServiceProvider` property that you can resolve service dependencies inside the `ConfigureBundle` method.
#### Standard Package Contributors
### Standard Package Contributors
Adding a specific NPM package resource (js, css files) into a bundle is pretty straight forward for that package. For example you always add the `bootstrap.css` file for the bootstrap NPM package.
@ -255,7 +284,7 @@ Using the built-in contributors for standard packages;
* Prevents multiple modules adding the **duplicate the files**.
* Manages **dependencies recursively** (adds dependencies of dependencies, if necessary).
##### Volo.Abp.AspNetCore.Mvc.UI.Packages Package
#### Volo.Abp.AspNetCore.Mvc.UI.Packages Package
> This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually.
@ -282,7 +311,7 @@ namespace MyCompany.MyProject
}
````
#### Bundle Inheritance
### Bundle Inheritance
In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle.
Example:
@ -302,11 +331,11 @@ services.Configure<BundlingOptions>(options =>
});
````
### Themes
## Themes
Themes uses the standard package contributors to add library resources to page layouts. Themes may also define some standard/global bundles, so any module can contribute to these standard/global bundles. See the [theming documentation](Theming.md) for more.
### Best Practices & Suggestions
## Best Practices & Suggestions
It's suggested to define multiple bundles for an application, each one is used for different purposes.
@ -317,7 +346,7 @@ It's suggested to define multiple bundles for an application, each one is used f
Establish a balance between performance, network bandwidth usage and count of many bundles.
### See Also
## See Also
* [Client Side Package Management](Client-Side-Package-Management.md)
* [Theming](Theming.md)

165
docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md

@ -0,0 +1,165 @@
# Dynamic C# API Clients
ABP can dynamically create C# API client proxies to call remote HTTP services (REST APIs). In this way, you don't need to deal with `HttpClient` and other low level HTTP features to call remote services and get results.
## Service Interface
Your service/controller should implement an interface that is shared between the server and the client. So, first define a service interface in a shared library project. Example:
````csharp
public interface IBookAppService : IApplicationService
{
Task<List<BookDto>> GetListAsync();
}
````
Your interface should implement the `IRemoteService` interface to be automatically discovered. Since the `IApplicationService` inherits the `IRemoteService` interface, the `IBookAppService` above satisfies this condition.
Implement this class in your service application. You can use [auto API controller system](Auto-API-Controllers.md) to expose the service as a REST API endpoint.
## Client Proxy Generation
First, add [Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget package to your client project:
````
Install-Package Volo.Abp.Http.Client
````
Then add `AbpHttpClientModule` dependency to your module:
````csharp
[DependsOn(typeof(AbpHttpClientModule))] //add the dependency
public class MyClientAppModule : AbpModule
{
}
````
Now, it's ready to create the client proxies. Example:
````csharp
[DependsOn(
typeof(AbpHttpClientModule), //used to create client proxies
typeof(BookStoreApplicationModule) //contains the application service interfaces
)]
public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Create dynamic client proxies
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly
);
}
}
````
`AddHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, creates and registers proxy classes.
### Endpoint Configuration
`RemoteServices` section in the `appsettings.json` file is used to get remote service address by default. Simplest configuration is shown below:
````
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
}
}
}
````
See the "RemoteServiceOptions" section below for more detailed configuration.
## Usage
It's straightforward to use. Just inject the service interface in the client application code:
````csharp
public class MyService : ITransientDependency
{
private readonly IBookAppService _bookService;
public MyService(IBookAppService bookService)
{
_bookService = bookService;
}
public async Task DoIt()
{
var books = await _bookService.GetListAsync();
foreach (var book in books)
{
Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}");
}
}
}
````
This sample injects the `IBookAppService` service interface defined above. The dynamic client proxy implementation makes an HTTP call whenever a service method is called by the client.
### IHttpClientProxy Interface
While you can inject `IBookAppService` like above to use the client proxy, you could inject `IHttpClientProxy<IBookAppService>` for a more explicit usage. In this case you will use the `Service` property of the `IHttpClientProxy<T>` interface.
## Configuration
### RemoteServiceOptions
`RemoteServiceOptions` is automatically set from the `appsettings.json` by default. Alternatively, you can use `Configure` method to set or override it. Example:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<RemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:53929/");
});
//...
}
````
### Multiple Remote Service Endpoints
The examples above have configured the "Default" remote service endpoint. You may have different endpoints for different services (as like in a microservice approach where each microservice has different endpoints). In this case, you can add other endpoints to your configuration file:
````json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
},
"BookStore": {
"BaseUrl": "http://localhost:48392/"
}
}
}
````
`AddHttpClientProxies` method can get an additional parameter for the remote service name. Example:
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
remoteServiceName: "BookStore"
);
````
`remoteServiceName` parameter matches the service endpoint configured via `RemoteServiceOptions`. If the `BookStore` endpoint is not defined then it fallbacks to the `Default` endpoint.
### As Default Services
When you create a service proxy for `IBookAppService`, you can directly inject the `IBookAppService` to use the proxy client (as shown in the usage section). You can pass `asDefaultServices: false` to the `AddHttpClientProxies` method to disable this feature.
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
asDefaultServices: false
);
````
Using `asDefaultServices: false` may only be needed if your application has already an implementation of the service and you do not want to override/replace the other implementation by your client proxy.
> If you disable `asDefaultServices`, you can only use `IHttpClientProxy<T>` interface to use the client proxies (see the related section above).

84
docs/en/Autofac-Integration.md

@ -0,0 +1,84 @@
# Autofac Integration
Autofac is one of the most used dependency injection frameworks for .Net. It provides some advanced features compared to .Net Core standard DI library, like dynamic proxying and property injection.
## Install Autofac Integration
> All startup templates and samples are Autofac integrated. So, most of the time you don't need to manually install this package.
Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget package to your project (for a multi-projects application, it's suggested to add to the executable/web project.)
````
Install-Package Volo.Abp.Autofac
````
Then add `AbpAutofacModule` dependency to your module:
```csharp
using Volo.Abp.Modularity;
using Volo.Abp.Autofac;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule
{
//...
}
}
```
Finally, configure `AbpApplicationCreationOptions` to replace default dependency injection services by Autofac. It depends on the application type.
### ASP.NET Core Application
Call `UseAutofac()` in the **Startup.cs** file as shown below:
````csharp
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<MyWebModule>(options =>
{
//Integrate Autofac!
options.UseAutofac();
});
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
````
### Console Application
Call `UseAutofac()` method in the `AbpApplicationFactory.Create` options as shown below:
````csharp
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); //Autofac integration
}))
{
//...
}
}
}
}
````

30
docs/en/Best-Practices/MongoDB-Integration.md

@ -103,34 +103,6 @@ public class IdentityMongoModelBuilderConfigurationOptions
}
```
* **Do** explicitly configure `BsonClassMap` for all entities. Create a static method for this purpose. Example:
````C#
public static class AbpIdentityBsonClassMap
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public static void Configure()
{
OneTimeRunner.Run(() =>
{
BsonClassMap.RegisterClassMap<IdentityUser>(map =>
{
map.AutoMap();
map.ConfigureExtraProperties();
});
BsonClassMap.RegisterClassMap<IdentityRole>(map =>
{
map.AutoMap();
});
});
}
}
````
`BsonClassMap` works with static methods. So, it is only needed to configure entities once in an application. `OneTimeRunner` guarantees that it runs in a thread safe manner and only once in the application life. Such a mapping above ensures that unit test properly run. This code will be called by the **module class** below.
### Repository Implementation
- **Do** **inherit** the repository from the `MongoDbRepository<TMongoDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:
@ -187,8 +159,6 @@ public class AbpIdentityMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
AbpIdentityBsonClassMap.Configure();
context.Services.AddMongoDbContext<AbpIdentityMongoDbContext>(options =>
{
options.AddRepository<IdentityUser, MongoIdentityUserRepository>();

86
docs/en/Dependency-Injection.md

@ -1,8 +1,10 @@
## Dependency Injection
# Dependency Injection
ABP's Dependency Injection system is developed based on Microsoft's [dependency injection extension](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) library (Microsoft.Extensions.DependencyInjection nuget package). So, it's documentation is valid in ABP too.
### Modularity
> While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work. Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information.
## Modularity
Since ABP is a modular framework, every module defines it's own services and registers via dependency injection in it's own seperate [module class](Module-Development-Basics.md). Example:
@ -16,7 +18,7 @@ public class BlogModule : AbpModule
}
````
### Conventional Registration
## Conventional Registration
ABP introduces conventional service registration. You need not do anything to register a service by convention. It's automatically done. If you want to disable it, you can set `SkipAutoServiceRegistration` to `true` by overriding the `PreConfigureServices` method.
@ -49,7 +51,7 @@ public class BlogModule : AbpModule
The section below explains the conventions and configurations.
#### Inherently Registered Types
### Inherently Registered Types
Some specific types are registered to dependency injection by default. Examples:
@ -71,7 +73,7 @@ public class BlogPostAppService : ApplicationService
``BlogPostAppService`` is automatically registered with transient lifetime since it's derived from a known base class.
#### Dependency Interfaces
### Dependency Interfaces
If you implement these interfaces, your class is registered to dependency injection automatically:
@ -89,7 +91,7 @@ public class TaxCalculator : ITransientDependency
``TaxCalculator`` is automatically registered with a transient lifetime since it implements ``ITransientDependency``.
#### Dependency Attribute
### Dependency Attribute
Another way of configuring a service for dependency injection is to use ``DependencyAttribute``. It has the following properties:
@ -110,7 +112,7 @@ public class TaxCalculator
``Dependency`` attribute has a higher priority than other dependency interfaces if it defines the ``Lifetime`` property.
#### ExposeServices Attribute
### ExposeServices Attribute
``ExposeServicesAttribute`` is used to control which services are provided by the related class. Example:
@ -124,14 +126,14 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie
``TaxCalculator`` class only exposes ``ITaxCalculator`` interface. That means you can only inject ``ITaxCalculator``, but can not inject ``TaxCalculator`` or ``ICalculator`` in your application.
#### Exposed Services by Convention
### Exposed Services by Convention
If you do not specify which services to expose, ABP expose services by convention. So taking the ``TaxCalculator`` defined above:
* The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not.
#### Combining All Together
### Combining All Together
Combining attributes and interfaces is possible as long as it's meaningful.
@ -144,7 +146,7 @@ public class TaxCalculator : ITaxCalculator, ITransientDependency
}
````
#### Manually Registering
### Manually Registering
In some cases, you may need to register a service to the `IServiceCollection` manually, especially if you need to use custom factory methods or singleton instances. In that case, you can directly add services just as [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) describes. Example:
@ -157,16 +159,18 @@ public class BlogModule : AbpModule
context.Services.AddSingleton<TaxCalculator>(new TaxCalculator(taxRatio: 0.18));
//Register a factory method that resolves from IServiceProvider
context.Services.AddScoped<ITaxCalculator>(sp => sp.GetRequiredService<TaxCalculator>());
context.Services.AddScoped<ITaxCalculator>(
sp => sp.GetRequiredService<TaxCalculator>()
);
}
}
````
### Injecting Dependencies
## Injecting Dependencies
There are three common ways of using a service that has already been registered.
#### Contructor Injection
### Contructor Injection
This is the most common way of injecting a service into a class. For example:
@ -191,7 +195,7 @@ public class TaxAppService : ApplicationService
Constructor injection is preffered way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services.
#### Property Injection
### Property Injection
Property injection is not supported by Microsoft Dependency Injection library. However, ABP can integrate with 3rd-party DI providers ([Autofac](https://autofac.org/), for example) to make property injection possible. Example:
@ -222,7 +226,7 @@ One restriction of property injection is that you cannot use the dependency in y
Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class.
#### Resolve Service from IServiceProvider
### Resolve Service from IServiceProvider
You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below:
@ -244,7 +248,7 @@ public class MyService : ITransientDependency
}
````
#### Releasing/Disposing Services
### Releasing/Disposing Services
If you used a constructor or property injection, you don't need to be concerned about releasing the service's resources. However, if you have resolved a service from ``IServiceProvider``, you might, in some cases, need to take care about releasing the service resources.
@ -266,6 +270,54 @@ using (var scope = _serviceProvider.CreateScope())
Both services are released when the created scope is disposed (at the end of the using block).
### See Also
## Advanced Features
### IServiceCollection.OnRegistred Event
You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistred` method as shown below:
````csharp
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
var type = ctx.ImplementationType;
//...
});
}
}
````
`ImplementationType` provides the service type. This callback is generally used to add interceptor to a service. Example:
````csharp
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true))
{
ctx.Interceptors.TryAdd<MyLogInterceptor>();
}
});
}
}
````
This example simply checks if the service class has `MyLogAttribute` attribute and adds `MyLogInterceptor` to the interceptor list if so.
> Notice that `OnRegistred` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors.
## 3rd-Party Providers
While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work.
Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information.
## See Also
* [ASP.NET Core Dependency Injection Best Practices, Tips & Tricks](https://medium.com/volosoft/asp-net-core-dependency-injection-best-practices-tips-tricks-c6e9c67f9d96)

3
docs/en/Dynamic-Proxying-Interceptors.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
TODO

2
docs/en/Entities.md

@ -41,7 +41,7 @@ public class UserRole : Entity
public DateTime CreationTime { get; set; }
public Phone()
public UserRole()
{
}

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

@ -1,8 +1,8 @@
## Entity Framework Core Integration
# Entity Framework Core Integration
This document explains how to integrate EF Core as an ORM provider to ABP based applications and how to configure it.
### Installation
## Installation
`Volo.Abp.EntityFrameworkCore` is the main nuget package for the EF Core integration. Install it to your project (for a layered application, to your data/infrastructure layer):
@ -28,7 +28,7 @@ namespace MyCompany.MyProject
> Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed.
### Creating DbContext
## Creating DbContext
You can create your DbContext as you normally do. It should be derived from `AbpDbContext<T>` as shown below:
@ -50,7 +50,21 @@ namespace MyCompany.MyProject
}
````
### Registering DbContext To Dependency Injection
### Configure the Connection String Selection
If you have multiple databases in your application, you can configure the connection string name for your DbContext using the `[ConnectionStringName]` attribute. Example:
```csharp
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpDbContext<MyDbContext>
{
}
```
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string.
## Registering DbContext To Dependency Injection
Use `AddAbpDbContext` method in your module to register your DbContext class for [dependency injection](Dependency-Injection.md) system.
@ -74,7 +88,7 @@ namespace MyCompany.MyProject
}
````
#### Add Default Repositories
### Add Default Repositories
ABP can automatically create default [generic repositories](Repositories.md) for the entities in your DbContext. Just use `AddDefaultRepositories()` option on the registration:
@ -137,7 +151,7 @@ public class BookManager : DomainService
This sample uses `InsertAsync` method to insert a new entity to the database.
#### Add Custom Repositories
### Add Custom Repositories
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods.
@ -173,7 +187,7 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed.
##### Override Default Generic Repository
#### Override Default Generic Repository
Even if you create a custom repository, you can still inject the default generic repository (`IRepository<Book, Guid>` for this example). Default repository implementation will not use the class you have created.
@ -199,7 +213,7 @@ public override async Task DeleteAsync(
}
````
#### Access to the EF Core API
### Access to the EF Core API
In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository). However, if you want to access the DbContext instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example:
@ -225,9 +239,9 @@ public class BookService
> Important: You must reference to the `Volo.Abp.EntityFrameworkCore` package from the project you want to access to the DbContext. This breaks encapsulation, but this is what you want in that case.
#### Advanced Topics
### Advanced Topics
##### Set Default Repository Classes
#### Set Default Repository Classes
Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for default repository implementation.
@ -272,7 +286,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
});
```
##### Set Base DbContext Class or Interface for Default Repositories
#### Set Base DbContext Class or Interface for Default Repositories
If your DbContext inherits from another DbContext or implements an interface, you can use that base class or interface as DbContext for default repositories. Example:
@ -304,7 +318,7 @@ public class BookRepository : EfCoreRepository<IBookStoreDbContext, Book, Guid>,
One advantage of using interface for a DbContext is then it becomes replaceable by another implementation.
##### Replace Other DbContextes
#### Replace Other DbContextes
Once you properly define and use an interface for DbContext, then any other implementation can replace it using the `ReplaceDbContext` option:

3
docs/en/Event-Bus.md

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

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

@ -1,8 +1,8 @@
## Getting Started ABP With AspNet Core MVC Web Application
# Getting Started ABP With AspNet Core MVC Web Application
This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with a **[startup template](https://abp.io/Templates)**.
This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with the **[startup template](Getting-Started-AspNetCore-MVC-Template.md)**.
### Create A New Project
## Create A New Project
1. Create a new empty AspNet Core Web Application from Visual Studio:
@ -14,7 +14,7 @@ This tutorial explains how to start ABP from scratch with minimal dependencies.
You could select another template, but I want to show it from a clear project.
### Install Volo.Abp.AspNetCore.Mvc Package
## Install Volo.Abp.AspNetCore.Mvc Package
Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, install it to your project:
@ -22,7 +22,7 @@ Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, inst
Install-Package Volo.Abp.AspNetCore.Mvc
````
### Create First ABP Module
## Create First ABP Module
ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``:
@ -62,7 +62,7 @@ ABP packages define module classes and a module can depend on another module. In
Instead of Startup class, we are configuring ASP.NET Core pipeline in this module class.
### The Startup Class
## The Startup Class
Next step is to modify Startup class to integrate to ABP module system:
@ -95,7 +95,7 @@ Changed ``ConfigureServices`` method to return ``IServiceProvider`` instead of `
``app.InitializeApplication()`` call in ``Configure`` method initializes and starts the application.
### Hello World!
## Hello World!
The application above does nothing. Let's create an MVC controller does something:
@ -120,13 +120,13 @@ If you run the application, you will see a "Hello World!" message on the page.
Derived ``HomeController`` from ``AbpController`` instead of standard ``Controller`` class. This is not required, but ``AbpController`` class has useful base properties and methods to make your development easier.
### Using Autofac as the Dependency Injection Framework
## Using Autofac as the Dependency Injection Framework
While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features.
Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy.
1. Install Volo.Abp.Autofac package
1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package
````
Install-Package Volo.Abp.Autofac
@ -152,6 +152,6 @@ services.AddApplication<AppModule>(options =>
});
````
### Source Code
## Source Code
Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication).

2
docs/en/Getting-Started-AspNetCore-MVC-Template.md

@ -1,5 +1,7 @@
## ASP.NET Core MVC Template
This tutorials explains how to create a new ASP.NET Core MVC web application using the startup template, configure and run it.
### Creating a new project
Go to [the template creation page](https://abp.io/Templates), enter a project name and create your project as shown below:

75
docs/en/Getting-Started-Console-Application.md

@ -1,14 +1,14 @@
## Getting Started ABP With Console Application
# Getting Started ABP With Console Application
This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with a **[startup template](https://abp.io/Templates)**.
### Create A New Project
## Create A New Project
Create a new Regular .Net Core Console Application from Visual Studio:
![](images/create-new-net-core-console-application.png)
### Install Volo.Abp Package
## Install Volo.Abp Package
Volo.Abp.Core is the core nuget package to create ABP based applications. So, install it to your project:
@ -16,7 +16,7 @@ Volo.Abp.Core is the core nuget package to create ABP based applications. So, in
Install-Package Volo.Abp.Core
````
### Create First ABP Module
## Create First ABP Module
ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``:
@ -35,7 +35,7 @@ namespace AbpConsoleDemo
``AppModule`` is a good name for the startup module for an application.
### Initialize The Application
## Initialize The Application
The next step is to bootstrap the application using the startup module created above:
@ -64,7 +64,7 @@ namespace AbpConsoleDemo
``AbpApplicationFactory`` is used to create the application and load all modules taking ``AppModule`` as the startup module. ``Initialize()`` method starts the application.
### Hello World!
## Hello World!
The application above does nothing. Let's create a service that does something:
@ -117,8 +117,65 @@ namespace AbpConsoleDemo
}
````
While it's enough for this simple code example, it's always suggested to create scopes in case of directly resolving dependencies from ``IServiceProvider`` (TODO: see DI documentation).
While it's enough for this simple code example, it's always suggested to create scopes in case of directly resolving dependencies from ``IServiceProvider`` (see the [Dependency Injection documentation](Dependency-Injection.md)).
### Source Code
## Using Autofac as the Dependency Injection Framework
Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication.
While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features.
Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy.
1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package
```
Install-Package Volo.Abp.Autofac
```
1. Add ``AbpAutofacModule`` Dependency
```c#
[DependsOn(typeof(AbpAutofacModule))] //Add dependency to the AbpAutofacModule
public class AppModule : AbpModule
{
}
```
1. Change ``Program.cs`` file as shown below:
```c#
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); //Autofac integration
}))
{
application.Initialize();
//Resolve a service and use it
var helloWorldService =
application.ServiceProvider.GetService<HelloWorldService>();
helloWorldService.SayHello();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
```
Just called `options.UseAutofac()` method in the `AbpApplicationFactory.Create` options.
## Source Code
Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication).

90
docs/en/Index.md

@ -1,66 +1,30 @@
# ABP Documentation
## Table of Contents
ABP is an **open source application framework** focused on ASP.NET Core based web application development, but also supports developing other types of applications.
* Getting Started
* From Startup Templates
* [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md)
* From Empty Projects
* [With Console Application](Getting-Started-Console-Application.md)
* [With ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md)
* Tutorials
* Application Development
* [With ASP.NET Core MVC](Tutorials/AspNetCore-Mvc/Part-I.md)
* Fundamentals
* [Dependency Injection](Dependency-Injection.md)
* AutoFac Integration
* [Virtual File System](Virtual-File-System.md)
* [Localization](Localization.md)
* [Exception Handling](Exception-Handling.md)
* Validation
* Authorization
* Caching
* Auditing
* Setting Management
* Object to Object Mapping
* AutoMapper Integration
* Events
* Event Bus (local)
* Distributed Event Bus
* RabbitMQ Integration
* Services
* Object Serialization
* JSON Serialization
* Emailing
* GUIDs
* Threading
* Timing
* [Multi Tenancy](Multi-Tenancy.md)
* Module Development
* [Basics](Module-Development-Basics.md)
* Plug-In Modules
* [Best Practices](Best-Practices/Index.md)
* Domain Driven Design
* Domain Layer
* [Entities & Aggregate Roots](Entities.md)
* Value Objects
* [Repositories](Repositories.md)
* Domain Services
* Specifications
* Application Layer
* Application Services
* Data Transfer Objects
* Unit Of Work
* ASP.NET Core MVC
* API Versioning
* User Interface
* [Client Side Package Management](AspNetCore/Client-Side-Package-Management.md)
* [Bundling & Minification](AspNetCore/Bundling-Minification.md)
* [Tag Helpers](Tag-Helpers.md)
* [Theming](AspNetCore/Theming.md)
* Data Access
* [Entity Framework Core Integration](Entity-Framework-Core.md)
* [MongoDB Integration](MongoDB.md)
* Background
* [Background Jobs](Background-Jobs.md)
* Testing
Explore the left navigation menu to deep dive in the documentation.
## Project Status
ABP is the **next generation** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. It's currently in early preview stage and not ready to use in production. The documentation is still in progress and it is incomplete yet.
For short-term and production level applications, it's suggested to use [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which has rich feature set, mature, actively maintained and up-to-date.
## Getting Started
Easiest way to start a new project with ABP is to use the startup templates:
* [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md)
If you want to start from scratch (with an empty project) then manually install the ABP Framework and use the following tutorials:
* [Console Application](Getting-Started-Console-Application.md)
* [ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md)
## Source Code
ABP is hosted on GitHub. See [the source code](https://github.com/abpframework/abp).
## Want to Contribute?
ABP is a community-driven open source project. See [the contribution guide](Contribution/Index.md) if you want to be a part of this project.

29
docs/en/Localization.md

@ -1,8 +1,8 @@
## Localization
# Localization
ABP's localization system is seamlessly integrated to the `Microsoft.Extensions.Localization` package and compatible with the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization). It adds some useful features and enhancements to make it easier to use in real life application scenarios.
### Volo.Abp.Localization Package
## Volo.Abp.Localization Package
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
@ -28,9 +28,9 @@ namespace MyCompany.MyProject
}
```
#### Creating A Localization Resource
## Creating A Localization Resource
A localization resource is used to group related localization strings together and separate them from other localization strings of the application. A module generally defines its own localization resource. Localization resource is just a plain class. Example:
A localization resource is used to group related localization strings together and separate them from other localization strings of the application. A [module](Module-Development-Basics.md) generally defines its own localization resource. Localization resource is just a plain class. Example:
````C#
public class TestResource
@ -52,7 +52,8 @@ public class MyModule : AbpModule
});
Configure<AbpLocalizationOptions>(options =>
{
{
//Define a new localization resource (TestResource)
options.Resources
.Add<TestResource>("en")
.AddVirtualJson("/Localization/Resources/Test");
@ -65,7 +66,7 @@ In this example;
* Added a new localization resource with "en" (English) as the default culture.
* Used JSON files to store the localization strings.
* JSON files are embedded into the assembly using the [virtual file system](Virtual-File-System.md).
* JSON files are embedded into the assembly using `VirtualFileSystemOptions` (see [virtual file system](Virtual-File-System.md)).
JSON files are located under "/Localization/Resources/Test" project folder as shown below:
@ -85,7 +86,7 @@ A JSON localization file content is shown below:
* Every localization file should define the `culture` code for the file (like "en" or "en-US").
* `texts` section just contains key-value collection of the localization strings (keys may have spaces too).
##### Short Localization Resource Name
### Short Localization Resource Name
Localization resources are also available in the client (JavaScript) side. So, setting a short name for the localization resource makes it easy to use localization texts. Example:
@ -98,7 +99,7 @@ public class TestResource
See the Getting Localized Test / Client Side section below.
##### Inherit From Other Resources
### Inherit From Other Resources
A resource can inherit from other resources which makes possible to re-use existing localization strings without referring the existing resource. Example:
@ -124,7 +125,7 @@ services.Configure<AbpLocalizationOptions>(options =>
* A resource may inherit from multiple resources.
* If the new resource defines the same localized string, it overrides the string.
##### Extending Existing Resource
### Extending Existing Resource
Inheriting from a resource creates a new resource without modifying the existing one. In some cases, you may want to not create a new resource but directly extend an existing resource. Example:
@ -139,13 +140,13 @@ services.Configure<AbpLocalizationOptions>(options =>
* If an extension file defines the same localized string, it overrides the string.
#### Getting Localized Texts
## Getting Localized Texts
##### Server Side
### Server Side
Getting the localized text on the server side is pretty standard.
###### Simplest Usage In A Class
#### Simplest Usage In A Class
````C#
public class MyService
@ -164,7 +165,7 @@ public class MyService
}
````
###### Simplest Usage In A Razor View/Page
#### Simplest Usage In A Razor View/Page
````c#
@inject IHtmlLocalizer<TestResource> Localizer
@ -174,7 +175,7 @@ public class MyService
Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using localization on the server side.
##### Client Side
### Client Side
ABP provides JavaScript services to use the same localized texts in the client side.

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.

33
docs/en/Module-Development-Basics.md

@ -1,10 +1,10 @@
## Module Development
# Module Development
### Introduction
## Introduction
ABP is itself a modular framework. It also provides an infrastructure and architectural model to develop your own modules.
ABP is a **modular application framework** which consists of dozens of **nuget packages**. It also provides a complete infrastructure to build your own application modules which may have entities, services, database integration, APIs, UI components and so on.
### Module Class
## Module Class
Every module should define a module class. The simplest way of defining a module class is to create a class derived from ``AbpModule`` as shown below:
@ -16,9 +16,9 @@ public class BlogModule : AbpModule
````
#### Configuring Dependency Injection & Other Modules
### Configuring Dependency Injection & Other Modules
##### ConfigureServices Method
#### ConfigureServices Method
``ConfigureServices`` is the main method to add your services to the dependency injection system and configure other modules. Example:
@ -52,15 +52,15 @@ public class BlogModule : AbpModule
See Configuration (TODO: link) document for more about the configuration system.
##### Pre & Post Configure Services
#### Pre & Post Configure Services
``AbpModule`` class also defines ``PreConfigureServices`` and ``PostConfigureServices`` methods to override and write your code just before and just after ``ConfigureServices``. Notice that the code you have written into these methods will be executed before/after the ``ConfigureServices`` methods of all other modules.
#### Application Initialization
### Application Initialization
Once all the services of all modules are configured, the application starts by initializing all modules. In this phase, you can resolve services from ``IServiceProvider`` since it's ready and available.
##### OnApplicationInitialization Method
#### OnApplicationInitialization Method
You can override ``OnApplicationInitialization`` method to execute code while application is being started. Example:
@ -102,15 +102,15 @@ public class AppModule : AbpModule
You can also perform startup logic if your module requires it
##### Pre & Post Application Initialization
#### Pre & Post Application Initialization
``AbpModule`` class also defines ``OnPreApplicationInitialization`` and ``OnPostApplicationInitialization`` methods to override and write your code just before and just after ``OnApplicationInitialization``. Notice that the code you have written into these methods will be executed before/after the ``OnApplicationInitialization`` methods of all other modules.
#### Application Shutdown
### Application Shutdown
Lastly, you can override ``OnApplicationShutdown`` method if you want to execute some code while application is beign shutdown.
Lastly, you can override ``OnApplicationShutdown`` method if you want to execute some code while application is being shutdown.
### Module Dependencies
## Module Dependencies
In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependcy upon another module, as shown below:
@ -126,3 +126,10 @@ public class BlogModule
You can use multiple ``DependsOn`` attribute or pass multiple module types to a single ``DependsOn`` attribute depending on your preference.
A depended module may depend on another module, but you only need to define your direct dependencies. ABP investigates the dependency graph for the application at startup and initializes/shutdowns modules in the correct order.
## Framework Modules vs Application Modules
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
- **Framework modules**: These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
- **Application modules**: These modules implement **specific application/business functionalities** like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components. See [pre-built application modules](Modules/Index.md).

475
docs/en/Modules/Docs.md

@ -0,0 +1,475 @@
# Docs Module
## What is Docs Module?
Docs module is an application module for ABP framework. It simplifies software documentation. This module is free and open-source.
### Integration
Currently docs module provides you to store your docs both on GitHub and file system.
### Hosting
Docs module is an application module and does not offer any hosting solution. You can host your docs on-premise or on cloud.
### Versioning
When you use GitHub to store your docs, Docs Module supports versioning. If you have multiple versions for your docs, there will be a combo-box on the UI to switch between versions. If you choose file system to store your docs, it does not support multiple versions.
[The documents](https://abp.io/documents/) for ABP framework is also using this module.
> Docs module follows the [module architecture best practices](../Best-Practices/Module-Architecture.md) guide.
## Installation
### 1- Download
If you do not have an existing ABP project, this step shows you how to create a new project from [abp.io](https://abp.io) to add the Docs Module. If you already have an ABP project, you can skip this step.
Navigate to https://abp.io/Templates. Enter your project name as `Acme.MyProject`, select `ASP.NET Core Mvc Application` and select `Entity Framework Core` for the database provider.
Note that this document covers `Entity Framework Core` provider but you can also select `MongoDB` as your database provider.
![Create new project](../images/docs-module_download-new-abp-project.png)
### 2- Running The Empty Application
After you download the project, extract the ZIP file and open `Acme.MyProject.sln`. You will see that the solution consists of `Application`, `Domain `, `EntityFrameworkCore` and `Web` projects. Right click on `Acme.MyProject.Web` project and **Set as StartUp Project**.
![Create a new project](../images/docs-module_solution-explorer.png)
The database connection string is located in `appsettings.json` of your `Acme.MyProject.Web` project. If you have a different database configuration, change the connection string.
```json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
```
Open `Package Manager Console` in the Visual Studio and choose `src\Acme.MyProject.EntityFrameworkCore` as the default project. Run `Update-Database` command to create your new database. The database `MyProject` will be created in your database server.
Now an empty ABP project has been created! You can now run your project and see the empty website.
To login your website enter `admin` as the username and `1q2w3E*` as the password.
### 2- Referencing Docs Module Packages
Docs module packages are hosted on NuGet. There are 4 packages that needs be to installed to your application. Each package has to be installed to the relevant project.
* [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) needs to be referenced to `Acme.MyProject.Domain` project.
* Edit `Acme.MyProject.Domain.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Domain" Version="0.9.0" />
```
* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) needs to be referenced to `Acme.MyProject.EntityFrameworkCore` project.
- Edit `Acme.MyProject.EntityFrameworkCore.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.EntityFrameworkCore" Version="0.9.0" />
```
* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) needs to be referenced to `Acme.MyProject.Application` project.
* Edit `Acme.MyProject.Application.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Application" Version="0.9.0" />
```
* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/)needs to be referenced to `Acme.MyProject.Web` project.
- Edit `Acme.MyProject.Web.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Web" Version="0.9.0" />
```
### 3- Adding Module Dependencies
An ABP module must declare `[DependsOn]` attribute if it has a dependency upon another module. Each module has to be added in`[DependsOn]` attribute to the relevant project.
* Open `MyProjectDomainModule.cs`and add `typeof(DocsDomainModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpAuditingModule),
typeof(BackgroundJobsDomainModule),
typeof(AbpAuditLoggingDomainModule)
)]
public class MyProjectDomainModule : AbpModule
{
//...
}
```
* Open `MyProjectEntityFrameworkCoreModule.cs`and add `typeof(DocsEntityFrameworkCoreModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsEntityFrameworkCoreModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(BackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule)
)]
public class MyProjectEntityFrameworkCoreModule : AbpModule
{
//...
}
```
* Open `MyProjectApplicationModule.cs`and add `typeof(DocsApplicationModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsApplicationModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityApplicationModule))]
public class MyProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<PermissionOptions>(options =>
{
options.DefinitionProviders.Add<MyProjectPermissionDefinitionProvider>();
});
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<MyProjectApplicationAutoMapperProfile>();
});
}
}
```
* Open `MyProjectWebModule.cs`and add `typeof(DocsWebModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsWebModule),
typeof(MyProjectApplicationModule),
typeof(MyProjectEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule)
)]
public class MyProjectWebModule : AbpModule
{
//...
}
```
### 4- Database Integration
#### 4.1- Entity Framework Integration
If you choose Entity Framework as your database provider, you need to configure the Docs Module in your DbContext. To do this;
- Open `MyProjectDbContext.cs` and add `modelBuilder.ConfigureDocs()` to the `OnModelCreating()`
```csharp
[ConnectionStringName("Default")]
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.ConfigureDocs();
}
}
```
* Open `Package Manager Console` in `Visual Studio` and choose `Acme.MyProject.EntityFrameworkCore` as default project. Then write the below command to add the migration for Docs Module.
```csharp
add-migration Added_Docs_Module
```
When the command successfully executes , you will see a new migration file named as `20181221111621_Added_Docs_Module` in the folder `Acme.MyProject.EntityFrameworkCore\Migrations`.
Now, update the database for Docs module database changes. To do this run the below code on `Package Manager Console` in `Visual Studio`. Be sure `Acme.MyProject.EntityFrameworkCore` is still default project.
```csharp
update-database
```
Finally, you can check your database to see the newly created tables. For example you can see `DocsProjects` table must be added to your database.
### 5- Linking Docs Module
The default route for Docs module is;
```
/Documents
```
To add Docs module link to your application menu;
* Open `MyProjectMenuContributor.cs` and add the below line to the method `ConfigureMainMenuAsync()`.
```csharp
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
```
Final look of **MyProjectMenuContributor.cs**
```csharp
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<MyProjectResource>>();
context.Menu.Items.Insert(0, new ApplicationMenuItem("MyProject.Home", l["Menu:Home"], "/"));
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
}
```
The `Menu:Docs` keyword is a localization key. To localize the menu text, open `Localization\MyProject\en.json` in the project `Acme.MyProject.Domain`. And add the below line
```json
"Menu:Docs": "Documents"
```
Final look of **en.json**
```json
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:Docs": "Documents"
}
}
```
The new menu item for Docs Module is added to the menu. Run your web application and browse to `http://localhost:YOUR_PORT_NUMBER/documents` URL.
You will see a warning says;
```
There are no projects yet!
```
As we have not added any projects yet, this warning is normal.
### 6- Adding New Docs Project
Open `DocsProjects` in your database, and insert a new record with the following field information;
* **Name**: The display name of the document name which will be shown on the web page.
* **ShortName**: A short and URL friendly name that will be used in your docs URL.
* **Format**: The format of the document (for Markdown: `md`, for HTML: `html`)
* **DefaultDocumentName**: The document for the initial page.
* **NavigationDocumentName**: The document to be used for the navigation menu (index).
* **MinimumVersion**: The minimum version to show the docs. Below version will not be listed.
* **DocumentStoreType**: The source of the documents (for GitHub:`GitHub`, for file system`FileSystem`)
* **ExtraProperties**: A serialized `JSON` that stores special configuration for the selected `DocumentStoreType`.
* **MainWebsiteUrl**: The URL when user clicks to the logo of the Docs module page. You can simply set as `/` to link to your website root address.
* **LatestVersionBranchName**: This is a config for GitHub. It's the branch name which to retrieve the docs. You can set it as `master`.
#### Sample Project Record for "GitHub"
You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documents to configure your GitHub document store.
- Name: `ABP framework (GitHub)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `GitHub`
- ExtraProperties:
```json
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}
```
Note that `GitHubAccessToken` is masked with `***`. It's a private token that you must get it from GitHub. See https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `master`
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}', N'/', N'master')
```
Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string.
#### Sample Project Record for "FileSystem"
You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documents to configure your GitHub document store.
- Name: `ABP framework (FileSystem)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `FileSystem`
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs\\en"}
```
Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs/en and copy to the directory `C:\\Github\\abp\\docs\\en` to get it work.
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `<NULL>`
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs\\en"}', N'/', NULL)
```
Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page.
So far, we have created a new application from abp.io website and made it up and ready for Docs module.
### 7- Creating a New Document
In the sample Project records, you see that `Format` is specified as `md` which refers to [Mark Down](https://en.wikipedia.org/wiki/Markdown). You can see the mark down cheat sheet following the below link;
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
ABP Docs Module can render mark down to HTML.
Now let's have a look a sample document in markdown format.
~~~markdown
# This is a header
Welcome to Docs Module.
## This is a sub header
[This is a link](https://abp.io)
![This is an image](https://abp.io/assets/my-image.png)
## This is a code block
```csharp
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
```
~~~
As an example you can see ABP Framework documentation:
[https://github.com/abpframework/abp/blob/master/docs/en/](https://github.com/abpframework/abp/blob/master/docs/en/)
### 8- Creating the Navigation Document
Navigation document is the main menu of the documents page. It is located on the left side of the page. It is a `JSON` file. Take a look at the below sample navigation document to understand the structure.
```json
{
"items":[
{
"text":"Sample Menu Item - 1",
"items":[
{
"text":"Sample Menu Item - 1.1",
"items":[
{
"text":"Sample Menu Item - 1.1.1",
"path":"SampleMenuItem_1_1_1.md"
}
]
},
{
"text":"Sample Menu Item - 1.2",
"items":[
{
"text":"Sample Menu Item - 1.2.1",
"path":"SampleMenuItem_1_2_1.md"
},
{
"text":"Sample Menu Item - 1.2.2",
"path":"SampleMenuItem_1_2_2.md"
}
]
}
]
},
{
"text":"Sample Menu Item - 2",
"items":[
{
"text":"Sample Menu Item - 2.1",
"items":[
{
"text":"Sample Menu Item - 2.1.1",
"path":"SampleMenuItem_2_1_1.md"
}
]
}
]
}
]
}
```
The upper sample `JSON` file renders the below navigation menu as `HTML`.
![Navigation menu](../images/docs-module_download-sample-navigation-menu.png)
Finally a new Docs Module is added to your project which is feeded with GitHub.

26
docs/en/Modules/Index.md

@ -0,0 +1,26 @@
# Application Modules
ABP is a **modular application framework** which consists of dozens of **nuget packages**. It also provides a complete infrastructure to build your own application modules which may have entities, services, database integration, APIs, UI components and so on.
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
* [**Framework modules**](https://github.com/abpframework/abp/tree/master/framework/src): These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
* [**Application modules**](https://github.com/abpframework/abp/tree/master/modules): These modules implement specific application/business functionalities like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components.
## Open Source Application Modules
There are some **free and open source** application modules developed and maintained by the ABP community:
* **Account**: Used to make user login/register to the application.
* **Audit Logging**: Used to persist audit logs to a database.
* **Background Jobs**: Used to persist background jobs when using default background job manager.
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://abp.io/documents/) already using this module.
* **Identity**: Used to manage roles, users and their permissions.
* **Identity Server**: Integrates to IdentityServer4.
* **Permission Management**: Used to persist permissions.
* **Setting Management**: Used to persist settings.
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Used the abstract users, so other modules can depend on this instead of the Identity module.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.

77
docs/en/MongoDB.md

@ -1,8 +1,8 @@
## MongoDB Integration
# MongoDB Integration
This document explains how to integrate MongoDB as a database provider to ABP based applications and how to configure it.
### Installation
## Installation
`Volo.Abp.MongoDB` is the main nuget package for the MongoDB integration. Install it to your project (for a layered application, to your data/infrastructure layer):
@ -26,7 +26,7 @@ namespace MyCompany.MyProject
}
```
### Creating a Mongo Db Context
## Creating a Mongo Db Context
ABP introduces **Mongo Db Context** concept (which is similar to Entity Framework Core's DbContext) to make it easier to use collections and configure them. An example is shown below:
@ -39,19 +39,62 @@ public class MyDbContext : AbpMongoDbContext
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
modelBuilder.Entity<Question>(b =>
{
b.CollectionName = "Questions";
});
base.CreateModel(modelBuilder);
//Customize the configuration for your collections.
}
}
```
* It's derived from `AbpMongoDbContext` class.
* Adds a public `IMongoCollection<TEntity>` property for each mongo collection. ABP uses these properties to create default repositories by default.
* Overriding `CreateModel` method allows to configure collections (like their collection name in the database).
* Overriding `CreateModel` method allows to configure collection configuration.
### Configure Mapping for a Collection
ABP automatically register entities to MongoDB client library for all `IMongoCollection<TEntity>` properties in your DbContext. For the example above, `Question` and `Category` entities are automatically registered.
For each registered entity, it calls `AutoMap()` and configures known properties of your entity. For instance, if your entity implements `IHasExtraProperties` interface (which is already implemented for every aggregate root by default), it automatically configures `ExtraProperties`.
So, most of times you don't need to explicitly configure registration for your entities. However, if you need it you can do it by overriding the `CreateModel` method in your DbContext. Example:
````csharp
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.Entity<Question>(b =>
{
b.CollectionName = "MyQuestions"; //Sets the collection name
b.BsonMap.UnmapProperty(x => x.MyProperty); //Ignores 'MyProperty'
});
}
````
This example changes the mapped collection name to 'MyQuestions' in the database and ignores a property in the `Question` class.
If you only need to configure the collection name, you can also use `[MongoCollection]` attribute for the collection in your DbContext. Example:
````csharp
[MongoCollection("MyQuestions")] //Sets the collection name
public IMongoCollection<Question> Questions => Collection<Question>();
````
### Configure the Connection String Selection
If you have multiple databases in your application, you can configure the connection string name for your DbContext using the `[ConnectionStringName]` attribute. Example:
````csharp
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpMongoDbContext
{
}
````
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string.
### Registering DbContext To Dependency Injection
## Registering DbContext To Dependency Injection
Use `AddAbpDbContext` method in your module to register your DbContext class for [dependency injection](Dependency-Injection.md) system.
@ -75,7 +118,7 @@ namespace MyCompany.MyProject
}
```
#### Add Default Repositories
### Add Default Repositories
ABP can automatically create default [generic repositories](Repositories.md) for the entities in your DbContext. Just use `AddDefaultRepositories()` option on the registration:
@ -138,7 +181,7 @@ public class BookManager : DomainService
This sample uses `InsertAsync` method to insert a new entity to the database.
#### Add Custom Repositories
### Add Custom Repositories
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods.
@ -182,7 +225,7 @@ public class BookRepository :
Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed.
##### Override Default Generic Repository
#### Override Default Generic Repository
Even if you create a custom repository, you can still inject the default generic repository (`IRepository<Book, Guid>` for this example). Default repository implementation will not use the class you have created.
@ -208,7 +251,7 @@ public override async Task DeleteAsync(
}
```
#### Access to the MongoDB API
### Access to the MongoDB API
In most cases, you want to hide MongoDB APIs behind a repository (this is the main purpose of the repository). However, if you want to access the MongoDB API over the repository, you can use `GetDatabase()` or `GetCollection()` extension methods. Example:
@ -232,9 +275,9 @@ public class BookService
> Important: You must reference to the `Volo.Abp.MongoDB` package from the project you want to access to the MongoDB API. This breaks encapsulation, but this is what you want in that case.
#### Advanced Topics
### Advanced Topics
##### Set Default Repository Classes
#### Set Default Repository Classes
Default generic repositories are implemented by `MongoDbRepository` class by default. You can create your own implementation and use it for default repository implementation.
@ -279,7 +322,7 @@ context.Services.AddMongoDbContext<BookStoreMongoDbContext>(options =>
});
```
##### Set Base MongoDbContext Class or Interface for Default Repositories
#### Set Base MongoDbContext Class or Interface for Default Repositories
If your MongoDbContext inherits from another MongoDbContext or implements an interface, you can use that base class or interface as the MongoDbContext for default repositories. Example:
@ -313,7 +356,7 @@ public class BookRepository
One advantage of using interface for a MongoDbContext is then it becomes replaceable by another implementation.
##### Replace Other DbContextes
#### Replace Other DbContextes
Once you properly define and use an interface for a MongoDbContext , then any other implementation can replace it using the `ReplaceDbContext` option:

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

@ -0,0 +1,40 @@
# Microservice Demo Solution
*"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](../Microservice-Architecture.md).
This sample aims to demonstrate a simple yet complete microservice solution;
* Has multiple, independent, self-deployable **microservices**.
* Multiple **web applications**, each uses a different API gateway.
* Has multiple **gateways** / BFFs (Backend for Frontends) developed using the [Ocelot](https://github.com/ThreeMammals/Ocelot) library.
* Has an **authentication service** developed using the [IdentityServer](https://identityserver.io/) framework. It's also a SSO (Single Sign On) application with necessary UIs.
* Has **multiple databases**. Some microservices has their own database while some services/applications shares a database (to demonstrate different use cases).
* Has different types of databases: **SQL Server** (with **Entity Framework Core** ORM) and **MongoDB**.
* Has a **console application** to show the simplest way of using a service by authenticating.
* Uses [Redis](https://redis.io/) for **distributed caching**.
* Uses [RabbitMQ](https://www.rabbitmq.com/) for service-to-service **messaging**.
* Uses [Kubernates](https://kubernetes.io/) to **deploy** & run all services and applications.
The diagram below shows the system:
![microservice-sample-diagram](../images/microservice-sample-diagram.png)
### Source Code
You can get the source code from [the GitHub repository](https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo).
### Status
This sample is still in development, not completed yet.
## Microservices
### Identity Service
...

12
docs/en/Tutorials/AspNetCore-Mvc/Part-I.md

@ -82,11 +82,11 @@ namespace Acme.BookStore
EF Core requires you to relate entities with your DbContext. The easiest way to do this is to add a `DbSet` property to the `BookStoreDbContext` class in the `Acme.BookStore.EntityFrameworkCore` project, as shown below:
````C#
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Book { get; set; }
...
}
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Book { get; set; }
...
}
````
#### Add New Migration & Update the Database
@ -236,7 +236,7 @@ namespace Acme.BookStore
You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX.
ABP can **automagically** configures your application services as MVC API Controllers by convention.
ABP can [**automagically**](../../AspNetCore/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention.
#### Swagger UI

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))
);
});

34
docs/en/docs-nav.json

@ -49,7 +49,8 @@
"path": "Dependency-Injection.md",
"items": [
{
"text": "AutoFac Integration"
"text": "AutoFac Integration",
"path": "Autofac-Integration.md"
}
]
},
@ -185,10 +186,20 @@
]
},
{
"text": "ASP.NET Core MVC",
"text": "ASP.NET Core",
"items": [
{
"text": "API Versioning"
"text": "API",
"items": [
{
"text": "Auto API Controllers",
"path": "AspNetCore/Auto-API-Controllers.md"
},
{
"text": "Dynamic C# API Clients",
"path": "AspNetCore/Dynamic-CSharp-API-Clients.md"
}
]
},
{
"text": "User Interface",
@ -245,6 +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/bookstore-apis.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/en/images/docs-module_download-new-abp-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/images/docs-module_download-sample-navigation-menu.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/docs-module_solution-explorer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

138
docs/zh-Hans/AspNetCore/Auto-API-Controllers.md

@ -0,0 +1,138 @@
# 自动API控制器
创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做.
ABP可以按照惯例 **自动** 将你的应用程序服务配置为MVC API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义.
## 配置
基本配置很简单. 只需配置`AbpAspNetCoreMvcOptions`并使用`ConventionalControllers.Create`方法,如下所示:
````csharp
[DependsOn(BookStoreApplicationModule)]
public class BookStoreWebModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
});
}
}
````
此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容.
![bookstore-apis](../images/bookstore-apis.png)
### 例子
一些示例方法名称和按约定生成的相应路由:
| 服务方法名称 | HTTP Method | 路由 |
| ----------------------------------------------------- | ----------- | -------------------------- |
| GetAsync(Guid id) | GET | /api/app/book/{id} |
| GetListAsync() | GET | /api/app/book |
| CreateAsync(CreateBookDto input) | POST | /api/app/book |
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} |
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} |
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors |
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor |
### HTTP Method
ABP在确定服务方法的HTTP Method时使用命名约定:
- **Get**: 如果方法名称以`GetList`,`GetAll`或`Get`开头.
- **Put**: 如果方法名称以`Put`或`Update`开头.
- **Delete**: 如果方法名称以`Delete`或`Remove`开头.
- **Post**: 如果方法名称以`Create`,`Add`,`Insert`或`Post`开头.
- **Patch**: 如果方法名称以`Patch`开头.
- 其他情况, **Post****默认方式**.
如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加[Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core)的Nuget包.
### 路由
路由根据一些惯例生成:
* 它始终以 **/api**开头.
* 接着是**路由路径**. 默认值为"**/app**", 可以进行如下配置:
````csharp
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.RootPath = "volosoft/book-store";
});
});
````
然后获得一本书的路由将是'**/api/volosoft/book-store/book/{id}**'. 此示例使用两级根路径,但通常使用单个级别的深度.
* 接着 **标准化控制器/服务名称**. 会删除`AppService`,`ApplicationService`和`Service`的后缀并将其转换为 **camelCase**. 如果你的应用程序服务类名称为`BookAppService`.那么它将变为`/book`.
* 如果要自定义命名, 则设置`UrlControllerNameNormalizer`选项. 它是一个委托允许你自定义每个控制器/服务的名称.
* 如果该方法具有 '**id**'参数, 则会在路由中添加'**/{id}**'.
* 如有必要,它会添加操作名称. 操作名称从服务上的方法名称获取并标准化;
* 删除'**Async**'后缀. 如果方法名称为'GetPhonesAsync',则变为`GetPhones`.
* 删除**HTTP method前缀**. 基于的HTTP method删除`GetList`,`GetAll`,`Get`,`Put`,`Update`,`Delete`,`Remove`,`Create`,`Add`,`Insert`,`Post`和`Patch`前缀, 因此`GetPhones`变为`Phones`, 因为`Get`前缀和GET请求重复.
* 将结果转换为**camelCase**.
* 如果生成的操作名称为**空**,则它不会添加到路径中.否则它会被添加到路由中(例如'/phones').对于`GetAllAsync`方法名称,它将为空,因为`GetPhonesAsync`方法名称将为`phone`.
* 可以通过设置`UrlActionNameNormalizer`选项来自定义.It's an action delegate that is called for every method.
* 如果有另一个带有'Id'后缀的参数,那么它也会作为最终路线段添加到路线中(例如'/phoneId').
## 服务选择
创建的HTTP API控制器并不是应用服务所独有的功能.
### IRemoteService 接口
如果一个类实现了`IRemoteService`接口, 那么它会被自动选择为API控制器. 由于应用程序服务本身实现了`IRemoteService`接口, 因此它自然就成为API控制器.
### RemoteService Attribute
`RemoteService`可用于将实现`IRemoteService`接口的类标记为远程服务或禁用它. 例如:
````csharp
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)]
public class PersonAppService : ApplicationService
{
}
````
### TypePredicate 选项
你可以通过提供`TypePedicate`选项进一步过滤类以成为API控制器:
````csharp
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.TypePredicate = type => { return true; };
});
});
````
如果你不想将此类型公开为API控制器, 则可以在类型检查时返回`false`.
## API Explorer
API Explorer是可以由客户端获取API结构的服务. Swagger使用它为endpoint创建文档和test UI.
默认情况下, HTTP API控制器会自动启用API Explorer, 可以使用`RemoteService`按类或方法的级别控制它. 例如:
````csharp
[RemoteService(IsMetadataEnabled = false)]
public class PersonAppService : ApplicationService
{
}
````
禁用`IsMetadataEnabled`从而从API Explorer中隐藏此服务, 并且无法被发现. 但是它仍然可以被知道确切API路径/路由的客户端使用.

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

@ -0,0 +1,165 @@
# 动态 C# API 客户端
ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 `HttpClient` 或者其他低级的HTTP功能调用远程服务并获取数据.
## 服务接口
你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如:
````csharp
public interface IBookAppService : IApplicationService
{
Task<List<BookDto>> GetListAsync();
}
````
为了能自动被发现,你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookAppService`完全满足这个条件.
在你的服务中实现这个类,你可以使用[auto API controller system](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点.
## 客户端代理生成
首先,将[Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget包添加到你的客户端项目中:
````
Install-Package Volo.Abp.Http.Client
````
然后给你的模块添加`AbpHttpClientModule`依赖:
````csharp
[DependsOn(typeof(AbpHttpClientModule))] //添加依赖
public class MyClientAppModule : AbpModule
{
}
````
现在,已经可以创建客户端代理了.例如:
````csharp
[DependsOn(
typeof(AbpHttpClientModule), //用来创建客户端代理
typeof(BookStoreApplicationModule) //包含应用服务接口
)]
public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//创建动态客户端代理
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly
);
}
}
````
`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类.
### Endpoint配置
`appsettings.json`文件中的`RemoteServices`节点被用来设置默认的服务地址.下面是最简单的配置:
````
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
}
}
}
````
查看下面的"RemoteServiceOptions"章节获取更多详细配置.
## 使用
可以很直接地使用.只需要在你的客户端程序中注入服务接口:
````csharp
public class MyService : ITransientDependency
{
private readonly IBookAppService _bookService;
public MyService(IBookAppService bookService)
{
_bookService = bookService;
}
public async Task DoIt()
{
var books = await _bookService.GetListAsync();
foreach (var book in books)
{
Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}");
}
}
}
````
本例注入了上面定义的`IBookAppService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用.
### IHttpClientProxy接口
你可以像上面那样注入`IBookAppService`来使用客户端代理,也可以注入`IHttpClientProxy<IBookAppService>`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy<T>`接口的`Service`属性.
## 配置
### RemoteServiceOptions
默认情况下`RemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<RemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:53929/");
});
//...
}
````
### 多个远程服务端点
上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点:
````json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
},
"BookStore": {
"BaseUrl": "http://localhost:48392/"
}
}
}
````
`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字:
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
remoteServiceName: "BookStore"
);
````
`remoteServiceName`参数会匹配通过`RemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点.
### 作为默认服务
当你为`IBookAppService`创建了一个服务代理,你可以直接注入`IBookAppService`来使用代理客户端(像上面章节中将的那样).你可以传递`asDefaultService:false`到`AddHttpClientProxies`方法来禁用此功能.
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
asDefaultServices: false
);
````
如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用`asDefaultServices:false`
> 如果你禁用了`asDefaultService`,你只能使用`IHttpClientProxy<T>`接口去使用客户端代理.(参见上面的相关章节).

84
docs/zh-Hans/Autofac-Integration.md

@ -0,0 +1,84 @@
# 集成 Autofac
Autofac 是.Net世界中最常用的依赖注入框架之一. 相比.Net Core标准的依赖注入库, 它提供了更多高级特性, 比如动态代理和属性注入.
## 安装 Autofac
> 所有的启动模板和示例都已经集成了 Autofac. 所以, 多数时候你无需手动安装这个包.
安装 [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget 包到你的项目 (对于一个多项目应用程序, 建议安装到可执行项目或者Web项目中.)
````
Install-Package Volo.Abp.Autofac
````
然后为你的模块添加 `AbpAutofacModule` 依赖:
```csharp
using Volo.Abp.Modularity;
using Volo.Abp.Autofac;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule
{
//...
}
}
```
最后, 配置 `AbpApplicationCreationOptions` 用 Autofac 替换默认的依赖注入服务. 根据应用程序类型, 情况有所不同.
### ASP.NET Core 应用程序
如下所示, 在 **Startup.cs** 文件中调用 `UseAutofac()`:
````csharp
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<MyWebModule>(options =>
{
//Integrate Autofac!
options.UseAutofac();
});
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
````
### 控制台应用程序
如下所示, 在 `AbpApplicationFactory.Create` 中用options调用 `UseAutofac()` 方法:
````csharp
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); //Autofac integration
}))
{
//...
}
}
}
}
````

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

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

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框架的完整的微服务的解决方案.

7
docs/zh-Hans/Module-Development-Basics.md

@ -125,3 +125,10 @@ public class BlogModule
你可以根据需要使用多个``DependsOn``属性或将多个模块类型传递给单个``DependsOn``属性.
依赖模块可能依赖于另一个模块,但你只需要定义直接依赖项.ABP在启动时会调查应用程序的依赖关系,并以正确的顺序初始化/关闭模块.
## 框架模块 vs 应用程序模块
**模块分为两种类型.** 这两种类型并没有任何结构上的区别,只是按功能和用途分类:
- **框架模块**: 这些是**框架的核心模块** 如缓存, 邮件, 主题, 安全, 序列化, 验证, EF Core集成, MongoDB集成... 等. 它们没有应用/业务功能,它们提供了日常开发经常用到的基础设施,集成和抽象.
- **应用程序模块**: 这些模块实现了 **特定的应用/业务功能** 像博客, 文档管理, 身份管理, 租房管理... 等等. 它们通过有自己的实体,服务,API和UI组件. 请参阅 [预构建的应用程序模块](Modules/Index.md).

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

@ -0,0 +1,467 @@
# 文档模块
## 什么是文档模块?
文档模块是ABP框架的一个应用程序模块. 它简化了软件文档的制作. 这个模块是开源免费的.
### 集成
目前文档模块提供提供了两种支持的存储,Github与文件系统.
### 托管
文档模块是一个应用程序模块,不提供任何托管的解决方案,你可以在本地或云上托管文档.
### 版本
当你使用GitHub存储文档时,文档模块支持多版本. 如果你的文档具有多个版本, UI上有一个组合框,用于切换版本. 如果你选择使用文件系统存储文档, 那么它不支持多版本.
ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
> 文档模块遵循 [模块化架构最佳实践](../Best-Practices/Module-Architecture.md) 指南.
## 安装
### 1- 下载
如果你没有现有的ABP项目, 这个步骤向你展示如何在[abp.io](https://cn.abp.io)创建一个新项目并添加文档模块. 如果你本地已经有了一个ABP项目, 那么你可以跳过这一步.
打开 https://cn.abp.io/Templates. 输入项目名称为 `Acme.MyProject`, 选择 `ASP.NET Core Mvc Application` 和选择 `Entity Framework Core` 做为数据库提供者.
请注意,本文档包含了 `Entity Framework Core` 提供者 不过你也可以选择 `MongoDB` 做为数据库提供者.
![创建新项目](../images/docs-module_download-new-abp-project.png)
### 2- 运行这个空项目
下载项目后, 解压压缩文档并且打开 `Acme.MyProject.sln`. 你可以看到这个解决方案包含了 `Application`, `Domain `, `EntityFrameworkCore``Web` 项目. 右键选择 `Acme.MyProject.Web` 项目**设置为启动项目**.
![创建新项目](../images/docs-module_solution-explorer.png)
数据库连接字符串位于`Acme.MyProject.Web`项目的`appsettings.json`中. 如果你有不同的数据库配置, 可以修改这个连接字符串.
```json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
```
打开Visual Studio包管理控制台选择`src\Acme.MyProject.EntityFrameworkCore` 做为默认项目. 运行 `Update-Database` 命令创建数据库. 数据库`MyProject`将在数据库服务器中创建.
现在一个空的ABP项目已经创建完成! 现在你可以运行项目并且查看网站.
输入用户名 `admin` 密码 `1q2w3E*` 登录到网站.
### 2- 引用文档模块包
文档模块包托管在Nuget上面. 需要有四个包安装到你的应用程序中. 每个包必须安装到相关的项目.
* [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) 需要安装到 `Acme.MyProject.Domain` 项目.
* 修改 `Acme.MyProject.Domain.csproj` 文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.Domain" Version="0.9.0" />
```
* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) 需要安装到 `Acme.MyProject.EntityFrameworkCore` 项目.
- 修改 `Acme.MyProject.EntityFrameworkCore.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.EntityFrameworkCore" Version="0.9.0" />
```
* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) 需要安装到 `Acme.MyProject.Application` 项目.
* 修改 `Acme.MyProject.Application.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.Application" Version="0.9.0" />
```
* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/) 需要安装到 `Acme.MyProject.Web` 项目.
- 修改 `Acme.MyProject.Web.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.Web" Version="0.9.0" />
```
### 3- 添加模块添加
一个ABP模块必须声明 `[DependsOn]` attribute 如果它依赖于另一个模块. 每个模块都必须在相关的项目的`[DependsOn]`Attribute 中添加.
* 打开 `MyProjectDomainModule.cs`并且添加 `typeof(DocsDomainModule)` 如下所示;
```csharp
[DependsOn(
typeof(DocsDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpAuditingModule),
typeof(BackgroundJobsDomainModule),
typeof(AbpAuditLoggingDomainModule)
)]
public class MyProjectDomainModule : AbpModule
{
//...
}
```
* 打开 `MyProjectEntityFrameworkCoreModule.cs`并且添加 `typeof(DocsEntityFrameworkCoreModule)` 如下所示;
```csharp
[DependsOn(
typeof(DocsEntityFrameworkCoreModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(BackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule)
)]
public class MyProjectEntityFrameworkCoreModule : AbpModule
{
//...
}
```
* 打开 `MyProjectApplicationModule.cs`并且添加 `typeof(DocsApplicationModule)` 如下所示;
```csharp
[DependsOn(
typeof(DocsApplicationModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityApplicationModule))]
public class MyProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<PermissionOptions>(options =>
{
options.DefinitionProviders.Add<MyProjectPermissionDefinitionProvider>();
});
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<MyProjectApplicationAutoMapperProfile>();
});
}
}
```
* 打开 `MyProjectWebModule.cs`并且添加 `typeof(DocsWebModule)` 如下所示;
```csharp
[DependsOn(
typeof(DocsWebModule),
typeof(MyProjectApplicationModule),
typeof(MyProjectEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule)
)]
public class MyProjectWebModule : AbpModule
{
//...
}
```
### 4- 数据库集成
#### 4.1- Entity Framework 集成
如果你选择了Entity Framework 做为数据库供应者,你需要在DbContext中配置文档模块. 做以下操作;
- 打开 `MyProjectDbContext.cs` 并且添加 `modelBuilder.ConfigureDocs()``OnModelCreating()` 方法中
```csharp
[ConnectionStringName("Default")]
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.ConfigureDocs();
}
}
```
* 打开 `Visual Studio``包管理控制台` 选择 `Acme.MyProject.EntityFrameworkCore` 做为默认项目. 然后编写以下命令为文档模块添加迁移.
```csharp
add-migration Added_Docs_Module
```
当命令执行成功后 , 你会看到`Acme.MyProject.EntityFrameworkCore\Migrations` 目录下有名为 `20181221111621_Added_Docs_Module` 的迁移文件.
现在更新数据库. 在 `Visual Studio``包管理控制台` 中执行以下代码. 要确认已 `Acme.MyProject.EntityFrameworkCore` 项目设置为默认项目.
```csharp
update-database
```
最后你可以查看数据库中创建的新表,例如你可以看到 `DocsProjects` 表已经添加到数据库中.
### 5- 链接文档模块
文档模块的默认路由是;
```
/Documents
```
添加文档模块的链接到你的应用程序菜单中;
* 打开 `MyProjectMenuContributor.cs` 并且在 `ConfigureMainMenuAsync()` 方法方法中添加以下代码.
```csharp
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
```
最后 **MyProjectMenuContributor.cs** 有以下内容
```csharp
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<MyProjectResource>>();
context.Menu.Items.Insert(0, new ApplicationMenuItem("MyProject.Home", l["Menu:Home"], "/"));
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
}
```
`Menu:Docs` 关键词是本地化的Key. 要本地化菜单文本, 打开`Acme.MyProject.Domain` 中的 `Localization\MyProject\zh-Hans.json`. 添加以下行.
```json
"Menu:Docs": "文档"
```
最后 **zh-Hans.json** 有以下内容
```json
{
"culture": "zh-Hans",
"texts": {
"Menu:Home": "首页",
"Welcome": "欢迎",
"LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 cn.abp.io.",
"Menu:Docs": "文档"
}
}
```
现在菜单中已经添加了文档模块项. 运行Web应用程序并且在浏览器中打开 `http://localhost:YOUR_PORT_NUMBER/documents` URL.
你会看到一个警告;
```
There are no projects yet!
```
这个警告是正常的,因为我们还没有添加任何项目.
### 6- 添加文档项目
在数据库中打开 `DocsProjects`, 并且插入包含以下字段的新记录;
* **Name**: 在Web页面上文档的显示名称.
* **ShortName**: 在文档URL中使用的友好的简短URL名称.
* **Format**: 文档的格式 ( Markdown: `md`, HTML: `html`)
* **DefaultDocumentName**: 文档的初始页面.
* **NavigationDocumentName**: 导航菜单(索引)的文档.
* **MinimumVersion**: 显示文档的最低版本. 低于此的版本不会列出.
* **DocumentStoreType**: 文档的来源 ( GitHub:`GitHub`,文件系统`FileSystem`).
* **ExtraProperties**: 序列化的`JSON`, 它存储所选 `DocumentStoreType` 的特殊配置.
* **MainWebsiteUrl**: 用户单击文档模块页面Logo时跳转的URL.你只需设置为`/`即可链接到网站根地址.
* **LatestVersionBranchName**: 这是GitHub的配置.它是检索文档的分支名称.你可以将其设置为`master`.
#### "GitHub" 项目的示例记录
你可以使用 [ABP Framework](https://github.com/abpframework/abp/) GitHub文档来配置Github文档存储.
- Name: `ABP framework (GitHub)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `GitHub`
- ExtraProperties:
```json
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/zh-Hans/","GitHubAccessToken":"***"}
```
注意 `GitHubAccessToken``***` 掩盖. 这是一个私人令牌,你必须从GitHub获取它. 请参阅 https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `master`
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/zh-Hans/","GitHubAccessToken":"***"}', N'/', N'master')
```
请注意,`GitHubAccessToken` 被屏蔽了.它是一个私人令牌,你必须获得自己的令牌并替换 `***` 字符串.
#### "FileSystem" 项目的示例记录
你可以使用 [ABP Framework](https://github.com/abpframework/abp/) GitHub文档来配置你的文件系统存储.
- Name: `ABP framework (FileSystem)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `FileSystem`
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs\\zh-Hans"}
```
请注意 `Path` 必须使用本地docs目录替换. 你可以从https://github.com/abpframework/abp/tree/master/docs/zh-hans获取ABP Framework的文档并且复制到该目录 `C:\\Github\\abp\\docs\\zh-Hans` 使其正常工作.
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `<NULL>`
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs\\zh-Hans"}', N'/', NULL)
```
添加上面的一个示例项目后运行该应用程序. 在菜单中你会看到`文档` 链接,点击菜单链接打开文档页面.
到目前为止, 我们已经从abp.io网站创建了一个新的应用程序,并为Docs模块做好准备.
### 7- 添加一个新文档
在示例项目记录中, 你可以看到 `Format` 被指定为 `md` 指的是 [Mark Down](https://en.wikipedia.org/wiki/Markdown). 你可以打开下面的链接查看语法;
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
ABP文档模块可以把MarkDown渲染为HTML.
现在让我们看一下Markdown格式的示例文档.
~~~markdown
# This is a header
Welcome to Docs Module.
## This is a sub header
[This is a link](https://abp.io)
![This is an image](https://abp.io/assets/my-image.png)
## This is a code block
```csharp
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
```
~~~
你可以使用 ABP Framework 的文档做为示例:
[https://github.com/abpframework/abp/blob/master/docs/zh-Hans/](https://github.com/abpframework/abp/blob/master/docs/zh-Hans/)
### 8- 创建文档导航
导航文档是文档页面的主菜单. 它位于页面的左侧,是一个`JSON` 文件. 请查看以下示例导航文档以了解结构.
```json
{
"items":[
{
"text":"Sample Menu Item - 1",
"items":[
{
"text":"Sample Menu Item - 1.1",
"items":[
{
"text":"Sample Menu Item - 1.1.1",
"path":"SampleMenuItem_1_1_1.md"
}
]
},
{
"text":"Sample Menu Item - 1.2",
"items":[
{
"text":"Sample Menu Item - 1.2.1",
"path":"SampleMenuItem_1_2_1.md"
},
{
"text":"Sample Menu Item - 1.2.2",
"path":"SampleMenuItem_1_2_2.md"
}
]
}
]
},
{
"text":"Sample Menu Item - 2",
"items":[
{
"text":"Sample Menu Item - 2.1",
"items":[
{
"text":"Sample Menu Item - 2.1.1",
"path":"SampleMenuItem_2_1_1.md"
}
]
}
]
}
]
}
```
上面的示例 `JSON` 文件将下面的导航菜单呈现为 `HTML` .
![Navigation menu](../images/docs-module_download-sample-navigation-menu.png)
最后,为您的项目添加了一个新的Docs模块, 该模块由GitHub提供.

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

@ -0,0 +1,26 @@
# 应用程序模块
ABP是一个 **模块化的应用程序框架** 由十多个 **nuget packages** 组成. 它提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块包含实体,服务,数据库集成,API,UI组件等.
**有两种类型的模块.** 它们没有任何结构上的差异,只是按照功能和目地分类:
* [**框架模块**](https://github.com/abpframework/abp/tree/master/framework/src): 这些是 **框架的核心模块**,像缓存,邮件,主题,安全性,序列化,验证,Ef Core集成,MongoDB集成...等等. 它们没有应用程序/业务功能,但通过提供通用基础架构,集成和抽象会使你的日常开发更加容易.
* [**应用程序模块**](https://github.com/abpframework/abp/tree/master/modules): 这些模块是实现特定的应用程序/业务功能,像 博客, 文档管理, 身份管理, 租户管理... 等等. 它是通常有自己的实体,服务,API和UI组件.
## 开源的应用程序模块
有一些由ABP社区开发和维护的 **开源免费** 的应用程序模块:
* **Account**: 用于用户登录/注册应用程序.
* **Audit Logging**: 用于将审计日志持久化到数据库.
* **Background Jobs**: 用于在使用默认后台作业管理器时保存后台作业.
* **Blogging**: 用于创建精美的博客. ABP的[博客](https://abp.io/blog/abp/) 就使用了此模块.
* [**Docs**](Docs.md): 用于创建技术文档页面. ABP的[文档](https://abp.io/documents/) 就使用了此模块.
* **Identity**: 用于管理角色,用户和他们的权限.
* **Identity Server**: 集成了IdentityServer4.
* **Permission Management**: 用于保存权限.
* **Setting Management**: 用于保存设置.
* **Tenant Management**: 用于管理[多租户](../Multi-Tenancy.md)应用程序的租户.
* **Users**: 用于抽象用户, 因此其他模块可以依赖此模块而不是Identity模块.
模块化文档正在编写中. 请参阅[这个仓库](https://github.com/abpframework/abp/tree/master/modules)获取所有模块的源代码.

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)获取源码.
### 状态
此示例仍处于开发阶段,尚未完成.
## 微服务
### 身份认证服务
...

2
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md

@ -238,7 +238,7 @@ namespace Acme.BookStore
你通常需要创建 **Controllers** 将应用服务暴露为 **HTTP API**.这样浏览器或第三方客户端可以通过AJAX的方式访问它们.
ABP可以 **自动地** 将应用服务转换成MVC API Controllers.
ABP可以 **自动地** (../../AspNetCore/Auto-API-Controllers.md)将应用服务转换成MVC API Controllers.
#### Swagger UI

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

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")
);
});

43
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"
}
]
@ -49,7 +49,8 @@
"path": "Dependency-Injection.md",
"items": [
{
"text": "AutoFac 集成"
"text": "AutoFac 集成",
"path": "Autofac-Integration.md"
}
]
},
@ -170,7 +171,8 @@
"text": "应用服务层",
"items": [
{
"text": "应用服务"
"text": "应用服务",
"path": "Application-Services.md"
},
{
"text": "数据传输对象(DTO)"
@ -183,10 +185,20 @@
]
},
{
"text": "ASP.NET Core MVC",
"text": "ASP.NET Core",
"items": [
{
"text": "API 版本控制"
"text": "API",
"items": [
{
"text": "自动API控制器",
"path": "AspNetCore/Auto-API-Controllers.md"
},
{
"text": "动态C# API客户端",
"path": "AspNetCore/Dynamic-CSharp-API-Clients.md"
}
]
},
{
"text": "用户界面",
@ -243,6 +255,23 @@
}
]
},
{
"text": "示例",
"items": [
{
"text": "微服务示例",
"path": "Samples/Microservice-Demo.md"
}
]
},
{
"text": "应用模块",
"path": "Modules/Index.md"
},
{
"text": "微服务架构",
"path": "Microservice-Architecture.md"
},
{
"text": "测试"
},
@ -251,4 +280,4 @@
"path": "Contribution/Index.md"
}
]
}
}

BIN
docs/zh-Hans/images/bookstore-apis.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/zh-Hans/images/docs-module_download-new-abp-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/zh-Hans/images/docs-module_solution-explorer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

46
framework/Volo.Abp.sln

@ -168,7 +168,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.MongoDB.Tests", "t
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.SqlServer", "src\Volo.Abp.EntityFrameworkCore.SqlServer\Volo.Abp.EntityFrameworkCore.SqlServer.csproj", "{6EABA98D-0B71-4ED7-A939-AFDA106D1151}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.RabbitMQ", "src\Volo.Abp.EventBus.Distributed.RabbitMQ\Volo.Abp.EventBus.RabbitMQ.csproj", "{468C3DCB-8C00-40E7-AE51-0738EAAB312A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.RabbitMQ", "src\Volo.Abp.EventBus.RabbitMQ\Volo.Abp.EventBus.RabbitMQ.csproj", "{468C3DCB-8C00-40E7-AE51-0738EAAB312A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj", "{2F5EE6D9-511B-4998-BD62-0B9F03E02432}"
EndProject
@ -212,7 +212,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.PostgreSql", "src\Volo.Abp.EntityFrameworkCore.PostgreSql\Volo.Abp.EntityFrameworkCore.PostgreSql.csproj", "{882E82F1-1A57-4BB9-B126-4CBF700C8F0C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Localization.Abstractions", "src\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj", "{20513A4E-FAC7-4106-8976-5D79A3BDFED1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Localization.Abstractions", "src\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj", "{20513A4E-FAC7-4106-8976-5D79A3BDFED1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Security.Tests", "test\Volo.Abp.Security.Tests\Volo.Abp.Security.Tests.csproj", "{7CE07034-7E02-4C78-B981-F1039412CA5E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Settings.Tests", "test\Volo.Abp.Settings.Tests\Volo.Abp.Settings.Tests.csproj", "{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.IdentityModel", "src\Volo.Abp.Http.Client.IdentityModel\Volo.Abp.Http.Client.IdentityModel.csproj", "{D211A446-38FA-4F97-9A95-1F004A0FFF69}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.IdentityModel", "src\Volo.Abp.IdentityModel\Volo.Abp.IdentityModel.csproj", "{64D99E19-EE25-465A-82E5-17B25F4C4E18}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Client", "src\Volo.Abp.AspNetCore.Mvc.Client\Volo.Abp.AspNetCore.Mvc.Client.csproj", "{E803DDB8-81EA-454B-9A66-9C2941100B67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Contracts", "src\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj", "{88F6D091-CA16-4B71-9499-8D5B8FA2E712}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -604,6 +616,30 @@ Global
{20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Release|Any CPU.Build.0 = Release|Any CPU
{7CE07034-7E02-4C78-B981-F1039412CA5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CE07034-7E02-4C78-B981-F1039412CA5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CE07034-7E02-4C78-B981-F1039412CA5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CE07034-7E02-4C78-B981-F1039412CA5E}.Release|Any CPU.Build.0 = Release|Any CPU
{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Release|Any CPU.Build.0 = Release|Any CPU
{D211A446-38FA-4F97-9A95-1F004A0FFF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D211A446-38FA-4F97-9A95-1F004A0FFF69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D211A446-38FA-4F97-9A95-1F004A0FFF69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D211A446-38FA-4F97-9A95-1F004A0FFF69}.Release|Any CPU.Build.0 = Release|Any CPU
{64D99E19-EE25-465A-82E5-17B25F4C4E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64D99E19-EE25-465A-82E5-17B25F4C4E18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64D99E19-EE25-465A-82E5-17B25F4C4E18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64D99E19-EE25-465A-82E5-17B25F4C4E18}.Release|Any CPU.Build.0 = Release|Any CPU
{E803DDB8-81EA-454B-9A66-9C2941100B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E803DDB8-81EA-454B-9A66-9C2941100B67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E803DDB8-81EA-454B-9A66-9C2941100B67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E803DDB8-81EA-454B-9A66-9C2941100B67}.Release|Any CPU.Build.0 = Release|Any CPU
{88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -707,6 +743,12 @@ Global
{77A621CF-9562-411B-A707-C7C02CC3B8FA} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{882E82F1-1A57-4BB9-B126-4CBF700C8F0C} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{20513A4E-FAC7-4106-8976-5D79A3BDFED1} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{7CE07034-7E02-4C78-B981-F1039412CA5E} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{D211A446-38FA-4F97-9A95-1F004A0FFF69} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{64D99E19-EE25-465A-82E5-17B25F4C4E18} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{E803DDB8-81EA-454B-9A66-9C2941100B67} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{88F6D091-CA16-4B71-9499-8D5B8FA2E712} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

8
framework/Volo.Abp.sln.DotSettings

@ -1,2 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=E193A13E6CDABC4687BFBCAD92DEDC16/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=E193A13E6CDABC4687BFBCAD92DEDC16/AbsolutePath/@EntryValue">D:\Github\abp\common.DotSettings</s:String>
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=E193A13E6CDABC4687BFBCAD92DEDC16/RelativePath/@EntryValue">..\..\common.DotSettings</s:String>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileE193A13E6CDABC4687BFBCAD92DEDC16/@KeyIndexDefined">True</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileE193A13E6CDABC4687BFBCAD92DEDC16/RelativePriority/@EntryValue">1</s:Double>
</wpf:ResourceDictionary>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj

@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OAuth" Version="2.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OAuth" Version="2.2.0" />
</ItemGroup>
</Project>

8
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs

@ -14,10 +14,10 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
Configure<TenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new QueryStringTenantResolveContributer());
options.TenantResolvers.Add(new RouteTenantResolveContributer());
options.TenantResolvers.Add(new HeaderTenantResolveContributer());
options.TenantResolvers.Add(new CookieTenantResolveContributer());
options.TenantResolvers.Add(new QueryStringTenantResolveContributor());
options.TenantResolvers.Add(new RouteTenantResolveContributor());
options.TenantResolvers.Add(new HeaderTenantResolveContributor());
options.TenantResolvers.Add(new CookieTenantResolveContributor());
});
}
}

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs

@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
public class CookieTenantResolveContributer : HttpTenantResolveContributerBase
public class CookieTenantResolveContributor : HttpTenantResolveContributorBase
{
protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext)
{

4
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs

@ -7,11 +7,11 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
//TODO: Create a better domain format. We can accept regex for example.
public class DomainTenantResolveContributer : HttpTenantResolveContributerBase
public class DomainTenantResolveContributor : HttpTenantResolveContributorBase
{
private readonly string _domainFormat;
public DomainTenantResolveContributer(string domainFormat)
public DomainTenantResolveContributor(string domainFormat)
{
_domainFormat = domainFormat.RemovePreFix("http://", "https://");
}

4
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs

@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
public class HeaderTenantResolveContributer : HttpTenantResolveContributerBase
public class HeaderTenantResolveContributor : HttpTenantResolveContributorBase
{
protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext)
{
@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
context
.ServiceProvider
.GetRequiredService<ILogger<HeaderTenantResolveContributer>>()
.GetRequiredService<ILogger<HeaderTenantResolveContributor>>()
.LogWarning(text);
}
}

4
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs

@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
public abstract class HttpTenantResolveContributerBase : ITenantResolveContributer
public abstract class HttpTenantResolveContributorBase : ITenantResolveContributor
{
public virtual void Resolve(ITenantResolveContext context)
{
@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
catch (Exception e)
{
context.ServiceProvider
.GetRequiredService<ILogger<HttpTenantResolveContributerBase>>()
.GetRequiredService<ILogger<HttpTenantResolveContributorBase>>()
.LogWarning(e.ToString());
}
}

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs

@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
public class QueryStringTenantResolveContributer : HttpTenantResolveContributerBase
public class QueryStringTenantResolveContributor : HttpTenantResolveContributorBase
{
protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext)
{

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs

@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
public class RouteTenantResolveContributer : HttpTenantResolveContributerBase
public class RouteTenantResolveContributor : HttpTenantResolveContributorBase
{
protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext)
{

4
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs

@ -8,8 +8,8 @@ namespace Volo.Abp.MultiTenancy
public static void AddDomainTenantResolver(this TenantResolveOptions options, string domainFormat)
{
options.TenantResolvers.InsertAfter(
r => r is CurrentClaimsPrincipalTenantResolveContributer,
new DomainTenantResolveContributer(domainFormat)
r => r is CurrentClaimsPrincipalTenantResolveContributor,
new DomainTenantResolveContributor(domainFormat)
);
}
}

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

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Client</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.Client</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<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" />
</ItemGroup>
</Project>

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

@ -0,0 +1,26 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
[DependsOn(
typeof(AbpHttpClientModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpCachingModule)
)]
public class AbpAspNetCoreMvcClientModule : AbpModule
{
public const string RemoteServiceName = "AbpMvcClient";
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(
typeof(AbpAspNetCoreMvcContractsModule).Assembly,
RemoteServiceName,
asDefaultServices: false
);
}
}
}

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

@ -0,0 +1,65 @@
using System;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class CachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency
{
public IHttpContextAccessor HttpContextAccessor { get; set; }
protected IHttpClientProxy<IAbpApplicationConfigurationAppService> Proxy { get; }
protected ICurrentUser CurrentUser { get; }
protected IDistributedCache<ApplicationConfigurationDto> Cache { get; }
public CachedApplicationConfigurationClient(
IDistributedCache<ApplicationConfigurationDto> cache,
IHttpClientProxy<IAbpApplicationConfigurationAppService> proxy,
ICurrentUser currentUser,
IHttpContextAccessor httpContextAccessor)
{
Proxy = proxy;
CurrentUser = currentUser;
HttpContextAccessor = httpContextAccessor;
Cache = cache;
}
public async Task<ApplicationConfigurationDto> GetAsync()
{
var cacheKey = CreateCacheKey();
var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext != null && httpContext.Items[cacheKey] is ApplicationConfigurationDto configuration)
{
return configuration;
}
configuration = await Cache.GetOrAddAsync(
CreateCacheKey(),
async () => await Proxy.Service.GetAsync(),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5)
}
);
if (httpContext != null)
{
httpContext.Items[cacheKey] = configuration;
}
return configuration;
}
protected virtual string CreateCacheKey()
{
return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}";
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public interface ICachedApplicationConfigurationClient
{
Task<ApplicationConfigurationDto> GetAsync();
}
}

32
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs

@ -0,0 +1,32 @@
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class RemotePermissionChecker : IPermissionChecker, ITransientDependency
{
protected ICachedApplicationConfigurationClient ConfigurationClient { get; }
public RemotePermissionChecker(ICachedApplicationConfigurationClient configurationClient)
{
ConfigurationClient = configurationClient;
}
public async Task<PermissionGrantInfo> CheckAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return new PermissionGrantInfo(
name,
configuration.Auth.GrantedPolicies.ContainsKey(name)
);
}
public Task<PermissionGrantInfo> CheckAsync(ClaimsPrincipal claimsPrincipal, string name)
{
return CheckAsync(name);
}
}
}

20
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Contracts</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.Contracts</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
</ItemGroup>
</Project>

13
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs

@ -0,0 +1,13 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc
{
[DependsOn(
typeof(AbpDddApplicationModule)
)]
public class AbpAspNetCoreMvcContractsModule : AbpModule
{
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs → framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs

@ -1,7 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
[Serializable]
public class ApplicationAuthConfigurationDto
{
public Dictionary<string, bool> Policies { get; set; }

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

@ -1,9 +1,14 @@
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
using System;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
[Serializable]
public class ApplicationConfigurationDto
{
public ApplicationLocalizationConfigurationDto Localization { get; set; }
public ApplicationAuthConfigurationDto Auth { get; set; }
public CurrentUserDto CurrentUser { get; set; }
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs → framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs

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

16
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs

@ -0,0 +1,16 @@
using System;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
[Serializable]
public class CurrentUserDto
{
public bool IsAuthenticated { get; set; }
public Guid? Id { get; set; }
public Guid? TenantId { get; set; }
public string UserName { get; set; }
}
}

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs → framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs

@ -1,8 +1,9 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
public interface IApplicationConfigurationBuilder
public interface IAbpApplicationConfigurationAppService : IApplicationService
{
Task<ApplicationConfigurationDto> GetAsync();
}

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

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
{
public class AbpTagHelperLocalizer : IAbpTagHelperLocalizer
{
private readonly IStringLocalizerFactory _stringLocalizerFactory;
private readonly AbpMvcDataAnnotationsLocalizationOptions _options;
public AbpTagHelperLocalizer(IOptions<AbpMvcDataAnnotationsLocalizationOptions> options, IStringLocalizerFactory stringLocalizerFactory)
{
_stringLocalizerFactory = stringLocalizerFactory;
_options = options.Value;
}
public string GetLocalizedText(string text, ModelExplorer explorer)
{
var resourceType = GetResourceTypeFromModelExplorer(explorer);
var localizer = GetStringLocalizer(resourceType);
return localizer == null ? text : localizer[text].Value;
}
public IStringLocalizer GetLocalizer(ModelExplorer explorer)
{
var resourceType = GetResourceTypeFromModelExplorer(explorer);
return GetStringLocalizer(resourceType);
}
public IStringLocalizer GetLocalizer(Assembly assembly)
{
var resourceType = _options.AssemblyResources.GetOrDefault(assembly);
return GetStringLocalizer(resourceType);
}
public IStringLocalizer GetLocalizer(Type resourceType)
{
return GetStringLocalizer(resourceType);
}
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);
}
}
}

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

@ -66,6 +66,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync)
{
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs

@ -8,6 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Alert
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.AddClass("alert-link");
output.Attributes.RemoveAll("abp-alert-link");
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public enum AbpButtonGroupDirection
{
Horizontal,
Vertical
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public enum AbpButtonGroupSize
{
Default,
Small,
Medium,
Large
}
}

15
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public class AbpButtonGroupTagHelper : AbpTagHelper<AbpButtonGroupTagHelper, AbpButtonGroupTagHelperService>
{
public AbpButtonGroupDirection Direction { get; set; } = AbpButtonGroupDirection.Horizontal;
public AbpButtonGroupSize Size { get; set; } = AbpButtonGroupSize.Default;
public AbpButtonGroupTagHelper(AbpButtonGroupTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

55
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs

@ -0,0 +1,55 @@
using System;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public class AbpButtonGroupTagHelperService : AbpTagHelperService<AbpButtonGroupTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
AddButtonGroupClass(context, output);
AddSizeClass(context, output);
AddAttributes(context, output);
}
protected virtual void AddSizeClass(TagHelperContext context, TagHelperOutput output)
{
switch (TagHelper.Size)
{
case AbpButtonGroupSize.Default:
break;
case AbpButtonGroupSize.Small:
output.Attributes.AddClass("btn-group-sm");
break;
case AbpButtonGroupSize.Medium:
output.Attributes.AddClass("btn-group-md");
break;
case AbpButtonGroupSize.Large:
output.Attributes.AddClass("btn-group-lg");
break;
}
}
protected virtual void AddButtonGroupClass(TagHelperContext context, TagHelperOutput output)
{
switch (TagHelper.Direction)
{
case AbpButtonGroupDirection.Horizontal:
output.Attributes.AddClass("btn-group");
break;
case AbpButtonGroupDirection.Vertical:
output.Attributes.AddClass("btn-group-vertical");
break;
default:
output.Attributes.AddClass("btn-group");
break;
}
}
protected virtual void AddAttributes(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.Add("role", "group");
}
}
}

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs

@ -5,6 +5,10 @@
Default,
Small,
Medium,
Large
Large,
Block,
Block_Small,
Block_Medium,
Block_Large,
}
}

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

@ -12,6 +12,14 @@
return "btn-md";
case AbpButtonSize.Large:
return "btn-lg";
case AbpButtonSize.Block:
return "btn-block";
case AbpButtonSize.Block_Small:
return "btn-sm btn-block";
case AbpButtonSize.Block_Medium:
return "btn-md btn-block";
case AbpButtonSize.Block_Large:
return "btn-lg btn-block";
case AbpButtonSize.Default:
return "";
default:

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

Loading…
Cancel
Save