diff --git a/.gitignore b/.gitignore
index cd63ac2e6c..9d3c3957aa 100644
--- a/.gitignore
+++ b/.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
diff --git a/README.md b/README.md
index 5074216c59..f6304ad5b3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# ABP
-[](http://vjenkins.dynu.net:5480/blue/organizations/jenkins/abp/activity)
+[](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 documentation .
#### Pre Requirements
-- Visual Studio 2017 15.7.0+
+- Visual Studio 2017 15.9.0+
#### Framework
diff --git a/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj b/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj
index ec07e51ed1..4a5c64eb64 100644
--- a/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj
+++ b/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
diff --git a/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj b/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj
index b0ac5294bc..b0c9926b35 100644
--- a/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj
+++ b/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
@@ -12,7 +12,7 @@
-
+
diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs
new file mode 100644
index 0000000000..9a3dd1e999
--- /dev/null
+++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs
@@ -0,0 +1,826 @@
+//
+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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
+ b.Property("Description")
+ .HasMaxLength(256);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("Regex")
+ .HasMaxLength(512);
+
+ b.Property("RegexDescription")
+ .HasMaxLength(128);
+
+ b.Property("Required");
+
+ b.Property("ValueType");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpClaimTypes");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDefault")
+ .HasColumnName("IsDefault");
+
+ b.Property("IsPublic")
+ .HasColumnName("IsPublic");
+
+ b.Property("IsStatic")
+ .HasColumnName("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName");
+
+ b.ToTable("AbpRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AbpRoleClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("AccessFailedCount")
+ .HasDefaultValue(0);
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Email")
+ .HasColumnName("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("EmailConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("LockoutEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("LockoutEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("LockoutEnd");
+
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("NormalizedEmail")
+ .HasColumnName("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .IsRequired()
+ .HasColumnName("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash")
+ .HasColumnName("PasswordHash")
+ .HasMaxLength(256);
+
+ b.Property("PhoneNumber")
+ .HasColumnName("PhoneNumber")
+ .HasMaxLength(16);
+
+ b.Property("PhoneNumberConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("PhoneNumberConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("SecurityStamp")
+ .IsRequired()
+ .HasColumnName("SecurityStamp")
+ .HasMaxLength(256);
+
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("TwoFactorEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("TwoFactorEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("TenantId");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AbpUserClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("ProviderDisplayName")
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(196);
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "LoginProvider");
+
+ b.HasIndex("LoginProvider", "ProviderKey");
+
+ b.ToTable("AbpUserLogins");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId", "UserId");
+
+ b.ToTable("AbpUserRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("Name")
+ .HasMaxLength(128);
+
+ b.Property("TenantId");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AbpUserTokens");
+ });
+
+ modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpPermissionGrants");
+ });
+
+ modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .HasMaxLength(64);
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(2048);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpSettings");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasColumnName("Description")
+ .HasMaxLength(1024);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnName("Name")
+ .HasMaxLength(256);
+
+ b.Property("ShortName")
+ .IsRequired()
+ .HasColumnName("ShortName")
+ .HasMaxLength(32);
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgBlogs");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Comments.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("PostId")
+ .HasColumnName("PostId");
+
+ b.Property("RepliedCommentId")
+ .HasColumnName("RepliedCommentId");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BlogId")
+ .HasColumnName("BlogId");
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("Content")
+ .HasColumnName("Content")
+ .HasMaxLength(1048576);
+
+ b.Property("CoverImage")
+ .IsRequired()
+ .HasColumnName("CoverImage");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("ReadCount");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnName("Title")
+ .HasMaxLength(512);
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnName("Url")
+ .HasMaxLength(64);
+
+ b.HasKey("Id");
+
+ b.HasIndex("BlogId");
+
+ b.ToTable("BlgPosts");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b =>
+ {
+ b.Property("PostId")
+ .HasColumnName("PostId");
+
+ b.Property("TagId")
+ .HasColumnName("TagId");
+
+ b.Property("CreationTime");
+
+ b.Property("CreatorId");
+
+ b.HasKey("PostId", "TagId");
+
+ b.HasIndex("TagId");
+
+ b.ToTable("BlgPostTags");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Tagging.Tag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BlogId");
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasColumnName("Description")
+ .HasMaxLength(512);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("UsageCount")
+ .HasColumnName("UsageCount");
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgTags");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Users.BlogUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("Email")
+ .HasColumnName("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("EmailConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("PhoneNumber")
+ .HasColumnName("PhoneNumber")
+ .HasMaxLength(16);
+
+ b.Property("PhoneNumberConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("PhoneNumberConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnName("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgUsers");
+ });
+
+ modelBuilder.Entity("Volo.Docs.Projects.Project", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("DefaultDocumentName")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("DocumentStoreType");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("Format");
+
+ b.Property("LatestVersionBranchName")
+ .HasMaxLength(128);
+
+ b.Property("MainWebsiteUrl");
+
+ b.Property("MinimumVersion");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("NavigationDocumentName")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ShortName")
+ .IsRequired()
+ .HasMaxLength(32);
+
+ b.HasKey("Id");
+
+ b.ToTable("DocsProjects");
+ });
+
+ modelBuilder.Entity("Volo.Utils.SolutionTemplating.DownloadInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationDuration");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DatabaseProvider");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("ProjectName")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("TemplateName")
+ .IsRequired()
+ .HasMaxLength(42);
+
+ b.Property("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
+ }
+ }
+}
diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs
new file mode 100644
index 0000000000..c354338499
--- /dev/null
+++ b/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(
+ name: "IsDeleted",
+ table: "AbpUsers",
+ nullable: false,
+ defaultValue: false,
+ oldClrType: typeof(bool));
+
+ migrationBuilder.AlterColumn(
+ name: "ConcurrencyStamp",
+ table: "AbpUsers",
+ nullable: true,
+ oldClrType: typeof(string),
+ oldMaxLength: 256);
+
+ migrationBuilder.AlterColumn(
+ name: "ConcurrencyStamp",
+ table: "AbpRoles",
+ maxLength: 256,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldNullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "ConcurrencyStamp",
+ table: "AbpClaimTypes",
+ maxLength: 256,
+ nullable: false,
+ defaultValue: "");
+
+ migrationBuilder.AddColumn(
+ 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(
+ name: "IsDeleted",
+ table: "AbpUsers",
+ nullable: false,
+ oldClrType: typeof(bool),
+ oldDefaultValue: false);
+
+ migrationBuilder.AlterColumn(
+ name: "ConcurrencyStamp",
+ table: "AbpUsers",
+ maxLength: 256,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldNullable: true);
+
+ migrationBuilder.AlterColumn(
+ name: "ConcurrencyStamp",
+ table: "AbpRoles",
+ nullable: true,
+ oldClrType: typeof(string),
+ oldMaxLength: 256);
+ }
+ }
+}
diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs
index f1af866317..b997aae5ca 100644
--- a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs
+++ b/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("Id")
.ValueGeneratedOnAdd();
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
b.Property("Description")
.HasMaxLength(256);
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
b.Property("IsStatic");
b.Property("Name")
@@ -53,7 +62,11 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property("Id")
.ValueGeneratedOnAdd();
- b.Property("ConcurrencyStamp");
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
b.Property("ExtraProperties")
.HasColumnName("ExtraProperties");
@@ -118,17 +131,20 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
.HasDefaultValue(0);
b.Property("ConcurrencyStamp")
- .IsRequired()
- .HasColumnName("ConcurrencyStamp")
- .HasMaxLength(256);
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
- b.Property("CreationTime");
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
- b.Property("CreatorId");
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
- b.Property("DeleterId");
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
- b.Property("DeletionTime");
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
b.Property("Email")
.HasColumnName("Email")
@@ -142,11 +158,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property("ExtraProperties")
.HasColumnName("ExtraProperties");
- b.Property("IsDeleted");
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
- b.Property("LastModificationTime");
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
- b.Property("LastModifierId");
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
b.Property("LockoutEnabled")
.ValueGeneratedOnAdd()
@@ -641,7 +662,9 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
b.Property("Id")
.ValueGeneratedOnAdd();
- b.Property("ConcurrencyStamp");
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
b.Property("DefaultDocumentName")
.IsRequired()
@@ -685,13 +708,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property("ConcurrencyStamp")
- .IsConcurrencyToken();
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
b.Property("CreationDuration");
- b.Property("CreationTime");
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
- b.Property("CreatorId");
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
b.Property("DatabaseProvider");
diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj
index 892d56593c..936a8cca19 100644
--- a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj
+++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
@@ -11,7 +11,7 @@
-
+
diff --git a/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs b/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
index a66d7bb11a..bbbce26cee 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
+++ b/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(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(options =>
+ {
+ options.Languages.Add(new LanguageInfo("en-US", "en-US", "English"));
+ });
+ }
+
private static void ConfigureBundles(IServiceCollection services)
{
services.Configure(options =>
@@ -112,14 +114,14 @@ namespace Volo.AbpWebSite
{
services.Configure(options =>
{
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(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(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar)));
- options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}account{0}src{0}Volo.Abp.Account.Web", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(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(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar)));
+ options.FileSets.ReplaceEmbeddedByPhysical(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()
- .SeedAsync(
- "1q2w3E*",
- IdentityPermissions.GetAll()
- .Union(BloggingPermissions.GetAll())
- );
- });
+ AsyncHelper.RunSync(async () =>
+ {
+ await scope.ServiceProvider
+ .GetRequiredService()
+ .SeedAsync(
+ "1q2w3E*"
+ );
+
+ await scope.ServiceProvider
+ .GetRequiredService()
+ .SeedAsync(
+ RolePermissionValueProvider.ProviderName,
+ "admin",
+ IdentityPermissions.GetAll().Union(BloggingPermissions.GetAll())
+ );
+ });
+ }
}
}
}
diff --git a/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml b/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
index bf74126618..010209c690 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
+++ b/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
@@ -195,34 +195,34 @@
-
+
-<abp-card>
- <img abp-card-image="Top" src="~/images/my-dog.png" />
- <abp-card-body>
- <abp-card-title>Card title</abp-card-title>
- <abp-card-text>
- <p>
- This is a sample card component built by ABP bootstrap
- card tag helper. ABP has tag helper wrappers for most of
- the bootstrap components.
- </p>
- </abp-card-text>
- <a abp-button="Primary" href="#">Go somewhere →</a>
- </abp-card-body>
-</abp-card>
+ <abp-card>
+ <img abp-card-image="Top" src="~/images/my-dog.png" />
+ <abp-card-body>
+ <abp-card-title>Card title</abp-card-title>
+ <abp-card-text>
+ <p>
+ This is a sample card component built by ABP bootstrap
+ card tag helper. ABP has tag helper wrappers for most of
+ the bootstrap components.
+ </p>
+ </abp-card-text>
+ <a abp-button="Primary" href="#">Go somewhere →</a>
+ </abp-card-body>
+ </abp-card>
-
+
-
+
@@ -265,7 +265,7 @@
-
+
@@ -300,12 +300,12 @@ public class PersonModel
-
+
-
+
diff --git a/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml b/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
index c3d877b425..8c25d6592b 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
+++ b/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
@@ -26,8 +26,7 @@
Github
-
diff --git a/abp_io/src/Volo.AbpWebSite.Web/Startup.cs b/abp_io/src/Volo.AbpWebSite.Web/Startup.cs
index 471337df1c..efbfda982a 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/Startup.cs
+++ b/abp_io/src/Volo.AbpWebSite.Web/Startup.cs
@@ -15,6 +15,7 @@ namespace Volo.AbpWebSite
services.AddApplication
(options =>
{
options.UseAutofac();
+ options.Configuration.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly;
});
return services.BuildServiceProviderFromFactory();
diff --git a/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj b/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
index 06fad8f448..8fbbbfd711 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
+++ b/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
Volo.AbpWebSite
$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
true
@@ -14,7 +14,7 @@
-
+
@@ -31,6 +31,8 @@
+
+
@@ -38,7 +40,7 @@
Always
-
+
Always
diff --git a/abp_io/src/Volo.AbpWebSite.Web/package-lock.json b/abp_io/src/Volo.AbpWebSite.Web/package-lock.json
new file mode 100644
index 0000000000..5e26238da6
--- /dev/null
+++ b/abp_io/src/Volo.AbpWebSite.Web/package-lock.json
@@ -0,0 +1,2758 @@
+{
+ "name": "volo.aspnetzero.support",
+ "version": "0.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@abp/anchor-js": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/anchor-js/-/anchor-js-0.5.1.tgz",
+ "integrity": "sha512-9N/iPP9tDdq9lKRNFQuqRL+QYSv5fq789KgHHGG1/MqExJ6KTPcqUDHvQ53kz96pUgJA+Fyn3dpwgPqLVYI3Yg==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "anchor-js": "^4.1.1"
+ }
+ },
+ "@abp/aspnetcore.mvc.ui": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-0.4.9.tgz",
+ "integrity": "sha512-AveMEi6WRQmD1tM9yVNLAe6ffcbtoL3ZGQKTPA95Q+dy5xBXVg4Y8jdhxawNPK64KYArhfrVkQDfa4mq3pW5Qw==",
+ "requires": {
+ "ansi-colors": "^1.1.0",
+ "extend-object": "^1.0.0",
+ "gulp": "^3.9.1",
+ "merge-stream": "^1.0.1",
+ "path": "^0.12.7",
+ "rimraf": "^2.6.2"
+ }
+ },
+ "@abp/aspnetcore.mvc.ui.theme.basic": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-0.4.9.tgz",
+ "integrity": "sha512-g3Zby8x8+vWw3oTJsSPasjm4tv7BG4270PEf7jK9w925+lIyKYHn6UxOcFbSU2pi9mJTnaF+Fk/rScIcdxwZZw==",
+ "requires": {
+ "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.9"
+ }
+ },
+ "@abp/aspnetcore.mvc.ui.theme.shared": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-0.4.9.tgz",
+ "integrity": "sha512-Fe4UfQ215Pz2V6D5HUYhDJFeJWjKLcv2gsZfOheWLlOBgYh274pdnUIwceoZ4Btpa9aPECLG+LAH4dTbs8vjRg==",
+ "requires": {
+ "@abp/aspnetcore.mvc.ui": "^0.4.9",
+ "@abp/bootstrap": "^0.4.9",
+ "@abp/datatables.net-bs4": "^0.4.9",
+ "@abp/font-awesome": "^0.4.9",
+ "@abp/jquery-form": "^0.4.9",
+ "@abp/jquery-validation-unobtrusive": "^0.4.9",
+ "@abp/lodash": "^0.4.9",
+ "@abp/select2": "^0.4.9",
+ "@abp/sweetalert": "^0.4.9",
+ "@abp/timeago": "^0.4.9",
+ "@abp/toastr": "^0.4.9"
+ }
+ },
+ "@abp/blogging": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/blogging/-/blogging-0.4.9.tgz",
+ "integrity": "sha512-cMFLekebHCM1ZAGPxcli3yzEy0kq1nV8ZuV9JbaczoiC/KDOnBp8CWq61CwLxgnfZpVIO5RTdtDye9pDtBJdmg==",
+ "requires": {
+ "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.9",
+ "@abp/owl.carousel": "^0.4.9",
+ "@abp/tui-editor": "^0.4.9"
+ }
+ },
+ "@abp/bootstrap": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/bootstrap/-/bootstrap-0.4.9.tgz",
+ "integrity": "sha512-A7lDHo43KnqjINo0xWECx/WzNQe3vqvE3GPv6uXq3KDi+gStQLAFBq3bVcVW/kSxiquDQ/tuCLRpE0qlhoobag==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "bootstrap": "^4.1.1"
+ }
+ },
+ "@abp/clipboard": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/clipboard/-/clipboard-0.5.1.tgz",
+ "integrity": "sha512-efOPloVL0moRqGpAMA7DU5o+vzzu7ipGOFcG9nOfDD6uGY9AsOztFc71GwIFrtwADvJSiJHD6OfEIfR++dCT0w==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "clipboard": "^2.0.4"
+ }
+ },
+ "@abp/codemirror": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/codemirror/-/codemirror-0.4.9.tgz",
+ "integrity": "sha512-bjuKZKLHyBzr6lWZ5Fh4Io/6u0OILkwsB9LJAZ3cHnDkmBEIRlnQBmuGxCkQ3D0sXcFWrLoqb2FAB9djLxCnUQ==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "codemirror": "^5.38.0"
+ }
+ },
+ "@abp/core": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/core/-/core-0.4.9.tgz",
+ "integrity": "sha512-JbibIPDz0w/C9YhexNagMD763qbZCclcHLVlTpKEZUcxzp6rZXwPR6ekh/PnvzD0R7wmHOh+bHl0hs5JSdy3oA=="
+ },
+ "@abp/datatables.net": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/datatables.net/-/datatables.net-0.4.9.tgz",
+ "integrity": "sha512-URimiGMFBusEMo9aAadLFCossbYyrN2R6+6YrQ+heqxdheCPmm2wupsXSFoUBHBhD0tzF4rY+OL//oOg3Wtg4g==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "datatables.net": "^1.10.16"
+ }
+ },
+ "@abp/datatables.net-bs4": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/datatables.net-bs4/-/datatables.net-bs4-0.4.9.tgz",
+ "integrity": "sha512-Dsz0fy2haBz3dl2MLXWjW2bhDBzp1cpWXSXj8TEEzYazjhyoqBy6AiFlEnRCqO49KZD6Ps1cONSRxx4c4On9Lg==",
+ "requires": {
+ "@abp/datatables.net": "^0.4.9",
+ "datatables.net-bs4": "^1.10.16"
+ }
+ },
+ "@abp/docs": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/docs/-/docs-0.5.1.tgz",
+ "integrity": "sha512-3pGYnxZxm2kYPfu2EwDF0QinsNTym2cWlYAo7mVUBuReTPMhwHYtgrE7AX3nCVv1iAo6ltW+mebonGt1s5yXzA==",
+ "requires": {
+ "@abp/anchor-js": "^0.5.1",
+ "@abp/clipboard": "^0.5.1",
+ "@abp/malihu-custom-scrollbar-plugin": "^0.5.1",
+ "@abp/popper.js": "^0.5.1",
+ "@abp/prismjs": "^0.5.1"
+ }
+ },
+ "@abp/font-awesome": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/font-awesome/-/font-awesome-0.4.9.tgz",
+ "integrity": "sha512-H4H/PJeSypoq++jP7eqS3y5jpbPIglUByPymHnho7U84gO06tZBUIoK00zyLACUVLzNztWANhmVqyA6OaHQ6xQ==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "font-awesome": "^4.7.0"
+ }
+ },
+ "@abp/highlight.js": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/highlight.js/-/highlight.js-0.4.9.tgz",
+ "integrity": "sha512-bsXgtOAJ8O4W3AO9arIxwLCC1JZABlZtoB55Pk5WjGiu8mhWiB4+HCXqWtSBE2qXwSLoDBE2FS5KAtIPfGfn+g==",
+ "requires": {
+ "@abp/core": "^0.4.9"
+ }
+ },
+ "@abp/jquery": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/jquery/-/jquery-0.4.9.tgz",
+ "integrity": "sha512-Lte2rfDhcVXRA18mJMyPs0oFoiX/7x10F9cwMyX4+8e9QulA0dg+MjJZ4HIbxRoKvaYPz0AdE5VZ511folFeTg==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "jquery": "^3.3.1"
+ }
+ },
+ "@abp/jquery-form": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/jquery-form/-/jquery-form-0.4.9.tgz",
+ "integrity": "sha512-T1LzHNO+L/ATSfsaSu9H5rq9oUGjjBrwcJBVQhWRuGbB/Nsv1t4CdCPZHqbYBsn3ji/6T9C80FMdL+s4iOfy8A==",
+ "requires": {
+ "@abp/jquery": "^0.4.9",
+ "jquery-form": "^4.2.2"
+ }
+ },
+ "@abp/jquery-validation": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/jquery-validation/-/jquery-validation-0.4.9.tgz",
+ "integrity": "sha512-8C58G9BTYszW6E0EO6NYqXLEbABXt/yGlOqAFCkPiLVfUcoC6uARqkgIgNVnE99ZUeSmluNsYeCczP0Qb0yNzg==",
+ "requires": {
+ "@abp/jquery": "^0.4.9",
+ "jquery-validation": "^1.17.0"
+ }
+ },
+ "@abp/jquery-validation-unobtrusive": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-0.4.9.tgz",
+ "integrity": "sha512-GR62QEPexX4uLcqF3y72V39nlx/70C7ubeaIxS1ZEq+0wGklwAiyq1p19qpB5Cuj2GJL+vFrIig5w+B79P2iAw==",
+ "requires": {
+ "@abp/jquery-validation": "^0.4.9",
+ "jquery-validation-unobtrusive": "^3.2.9"
+ }
+ },
+ "@abp/lodash": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/lodash/-/lodash-0.4.9.tgz",
+ "integrity": "sha512-/itYbXQL145WigKIGpnyWgARml7QGie7xqhC1WZG5iUkdqLx+4YBXesdzGFykthDewiQNz8mB2gPk64d376AAw==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "lodash": "^4.17.10"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ }
+ }
+ },
+ "@abp/malihu-custom-scrollbar-plugin": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-0.5.1.tgz",
+ "integrity": "sha512-i9XorWsWcqb3tbbiwvE4OQCfXXJO38HlkQgvlwzxshB8xDcS9v/JL5fAAvM/Cr66fB2zybsrCseq9QcBXL+yCQ==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "malihu-custom-scrollbar-plugin": "^3.1.5"
+ }
+ },
+ "@abp/markdown-it": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/markdown-it/-/markdown-it-0.4.9.tgz",
+ "integrity": "sha512-leaY6Iom4zCW9RcZWIZbiYTM8NTmSYSa2Xiq7FW2MzhDCATXbcqV1+EqNAAFBERHAJoq0Hyz2AkIP510L+hz6Q==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "markdown-it": "^8.4.1"
+ }
+ },
+ "@abp/owl.carousel": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/owl.carousel/-/owl.carousel-0.4.9.tgz",
+ "integrity": "sha512-pgRcdbN1u6vaN6wOfNN9z6Id70va93kGTCBNVY43fJec1ghIq/evpBNp29ef5x9b0lcfe4DhmNb3CFaLbikr0w==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "owl.carousel": "^2.3.4"
+ }
+ },
+ "@abp/popper.js": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/popper.js/-/popper.js-0.5.1.tgz",
+ "integrity": "sha512-qS97hQQtG78mVPRvmZZtBb7Vu905NpThl9PN3jPWWDiVbOV2/d+BXCTRhTRbfdup3C5cmGdntjaGxfcxlxHt1Q==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "popper.js": "^1.14.6"
+ }
+ },
+ "@abp/prismjs": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@abp/prismjs/-/prismjs-0.5.1.tgz",
+ "integrity": "sha512-DxoidAVV8LmtgFonbzGJEfszQDUaHEQc+/bcJtyQCuv5l+uflVnpAH+6W8IAErt5N96a0RJbeV9ZBXjIhqOzpA==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "prismjs": "^1.15.0"
+ }
+ },
+ "@abp/select2": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/select2/-/select2-0.4.9.tgz",
+ "integrity": "sha512-AaJHWy9fkP/LqVkruZGfvzgdZXyT96/FpnflUpoNPXjuvVRptkJpd/BQiWjpyjS+qzuZ+m3X9dms0d0lAyFKYA==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "select2": "^4.0.5"
+ }
+ },
+ "@abp/sweetalert": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/sweetalert/-/sweetalert-0.4.9.tgz",
+ "integrity": "sha512-FaxtELo7Um/uasasbOGi1j1XuBtZ819mUo7+6pMSWj2CSAkg2A/RyT9NhYcX8oyGpv188W5CjZfJ1DM0bRH+pQ==",
+ "requires": {
+ "@abp/core": "^0.4.9",
+ "sweetalert": "^2.1.0"
+ }
+ },
+ "@abp/timeago": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/timeago/-/timeago-0.4.9.tgz",
+ "integrity": "sha512-RsAyJCl+rEWQL0q0Nx/ijy+iOBYm5IC5Re6y4SQ1jYF/B4n88GM2PFy6kLrE+HHGl5Z5hkWr5OGXmFem50Y3Wg==",
+ "requires": {
+ "@abp/jquery": "^0.4.9",
+ "timeago": "^1.6.3"
+ }
+ },
+ "@abp/toastr": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/toastr/-/toastr-0.4.9.tgz",
+ "integrity": "sha512-KjnETa1Og5EIMDw/pIxPoKLTABBcsxBN8BqwIG33ya2+BIRfAI7b0lEMoKK+qmwVwI5dkXZlKFGIUmPtb+zVCw==",
+ "requires": {
+ "@abp/jquery": "^0.4.9",
+ "toastr": "^2.1.4"
+ }
+ },
+ "@abp/tui-editor": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/@abp/tui-editor/-/tui-editor-0.4.9.tgz",
+ "integrity": "sha512-sIXF/rNX2UyQiDCDmj8pv1FeqtAv9B0NquyBJwWDkaXWQsmJJ3YU/drcJHbzabsYg2tBjzRM/4Bb0+eXYR+Mnw==",
+ "requires": {
+ "@abp/codemirror": "^0.4.9",
+ "@abp/highlight.js": "^0.4.9",
+ "@abp/jquery": "^0.4.9",
+ "@abp/markdown-it": "^0.4.9",
+ "tui-editor": "^1.2.6"
+ }
+ },
+ "almond": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz",
+ "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA="
+ },
+ "anchor-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/anchor-js/-/anchor-js-4.1.1.tgz",
+ "integrity": "sha512-c2Wl9F1X0C4jkYKLla1SNE2uI6xJrSKsRC7HCCg4yLNQ5sL5D+tDEWrjRaoTuTlMTqBCnF6kOuR3dx59Erxpvw=="
+ },
+ "ansi-colors": {
+ "version": "1.1.0",
+ "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+ "requires": {
+ "ansi-wrap": "^0.1.0"
+ }
+ },
+ "ansi-gray": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+ "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
+ "requires": {
+ "ansi-wrap": "0.1.0"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+ },
+ "ansi-wrap": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+ "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768="
+ },
+ "archy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
+ },
+ "array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
+ },
+ "array-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8="
+ },
+ "array-slice": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w=="
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
+ },
+ "babel-polyfill": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
+ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "core-js": "^2.5.0",
+ "regenerator-runtime": "^0.10.5"
+ }
+ },
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+ }
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "beeper": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
+ "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak="
+ },
+ "bootstrap": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz",
+ "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w=="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clipboard": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz",
+ "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==",
+ "requires": {
+ "good-listener": "^1.2.2",
+ "select": "^1.1.2",
+ "tiny-emitter": "^2.0.0"
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
+ },
+ "clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE="
+ },
+ "codemirror": {
+ "version": "5.40.2",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.40.2.tgz",
+ "integrity": "sha512-yoWuvEiD3v5vTwdoMc/wu/Ld6dh9K/yEiEBTKOPGM+/pN0gTAqFNtrLHv1IJ1UJvzFpNRvMi92XCi3+8/iIaEw=="
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
+ },
+ "core-js": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "datatables.net": {
+ "version": "1.10.19",
+ "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.19.tgz",
+ "integrity": "sha512-+ljXcI6Pj3PTGy5pesp3E5Dr3x3AV45EZe0o1r0gKENN2gafBKXodVnk2ypKwl2tTmivjxbkiqoWnipTefyBTA==",
+ "requires": {
+ "jquery": ">=1.7"
+ }
+ },
+ "datatables.net-bs4": {
+ "version": "1.10.19",
+ "resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.19.tgz",
+ "integrity": "sha512-pgeP17w4aPR7HIxIwuJghfqXULjdg1K6xMUUKDyCERJRSNNK4MRToFfELtIsluLNN555YBK4Kx8nihX5/ZT1Fw==",
+ "requires": {
+ "datatables.net": "1.10.19",
+ "jquery": ">=1.7"
+ }
+ },
+ "dateformat": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
+ "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ },
+ "defaults": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "delegate": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
+ "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
+ },
+ "deprecated": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz",
+ "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk="
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc="
+ },
+ "duplexer2": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
+ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
+ "requires": {
+ "readable-stream": "~1.1.9"
+ }
+ },
+ "end-of-stream": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz",
+ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=",
+ "requires": {
+ "once": "~1.3.0"
+ }
+ },
+ "entities": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
+ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
+ },
+ "es6-object-assign": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
+ "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "eve": {
+ "version": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1",
+ "from": "git://github.com/adobe-webplatform/eve.git#eef80ed"
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extend-object": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz",
+ "integrity": "sha1-QlFPhAFdE1bK9Rh5ad+yvBvaCCM="
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "fancy-log": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz",
+ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=",
+ "requires": {
+ "ansi-gray": "^0.1.1",
+ "color-support": "^1.1.3",
+ "time-stamp": "^1.0.0"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "find-index": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz",
+ "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ="
+ },
+ "findup-sync": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^3.1.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "fined": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz",
+ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=",
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "is-plain-object": "^2.0.3",
+ "object.defaults": "^1.1.0",
+ "object.pick": "^1.2.0",
+ "parse-filepath": "^1.0.1"
+ }
+ },
+ "first-chunk-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
+ "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04="
+ },
+ "flagged-respawn": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz",
+ "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c="
+ },
+ "font-awesome": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
+ "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+ },
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "gaze": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
+ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=",
+ "requires": {
+ "globule": "~0.1.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
+ },
+ "glob": {
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz",
+ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=",
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^2.0.1",
+ "once": "^1.3.0"
+ }
+ },
+ "glob-stream": {
+ "version": "3.1.18",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz",
+ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=",
+ "requires": {
+ "glob": "^4.3.1",
+ "glob2base": "^0.0.12",
+ "minimatch": "^2.0.1",
+ "ordered-read-streams": "^0.1.0",
+ "through2": "^0.6.1",
+ "unique-stream": "^1.0.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ }
+ }
+ },
+ "glob-watcher": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz",
+ "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=",
+ "requires": {
+ "gaze": "^0.5.1"
+ }
+ },
+ "glob2base": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
+ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=",
+ "requires": {
+ "find-index": "^0.1.1"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globule": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
+ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=",
+ "requires": {
+ "glob": "~3.1.21",
+ "lodash": "~1.0.1",
+ "minimatch": "~0.2.11"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "3.1.21",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
+ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
+ "requires": {
+ "graceful-fs": "~1.2.0",
+ "inherits": "1",
+ "minimatch": "~0.2.11"
+ }
+ },
+ "graceful-fs": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
+ "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q="
+ },
+ "inherits": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
+ "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js="
+ },
+ "minimatch": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
+ "requires": {
+ "lru-cache": "2",
+ "sigmund": "~1.0.0"
+ }
+ }
+ }
+ },
+ "glogg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz",
+ "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==",
+ "requires": {
+ "sparkles": "^1.0.0"
+ }
+ },
+ "good-listener": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
+ "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
+ "requires": {
+ "delegate": "^3.1.2"
+ }
+ },
+ "graceful-fs": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
+ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
+ "requires": {
+ "natives": "^1.1.0"
+ }
+ },
+ "gulp": {
+ "version": "3.9.1",
+ "resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz",
+ "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=",
+ "requires": {
+ "archy": "^1.0.0",
+ "chalk": "^1.0.0",
+ "deprecated": "^0.0.1",
+ "gulp-util": "^3.0.0",
+ "interpret": "^1.0.0",
+ "liftoff": "^2.1.0",
+ "minimist": "^1.1.0",
+ "orchestrator": "^0.3.0",
+ "pretty-hrtime": "^1.0.0",
+ "semver": "^4.1.0",
+ "tildify": "^1.0.0",
+ "v8flags": "^2.0.2",
+ "vinyl-fs": "^0.3.0"
+ }
+ },
+ "gulp-util": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
+ "requires": {
+ "array-differ": "^1.0.0",
+ "array-uniq": "^1.0.2",
+ "beeper": "^1.0.0",
+ "chalk": "^1.0.0",
+ "dateformat": "^2.0.0",
+ "fancy-log": "^1.1.0",
+ "gulplog": "^1.0.0",
+ "has-gulplog": "^0.1.0",
+ "lodash._reescape": "^3.0.0",
+ "lodash._reevaluate": "^3.0.0",
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.template": "^3.0.0",
+ "minimist": "^1.1.0",
+ "multipipe": "^0.1.2",
+ "object-assign": "^3.0.0",
+ "replace-ext": "0.0.1",
+ "through2": "^2.0.0",
+ "vinyl": "^0.5.0"
+ }
+ },
+ "gulplog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+ "requires": {
+ "glogg": "^1.0.0"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "has-gulplog": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
+ "requires": {
+ "sparkles": "^1.0.0"
+ }
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "highlight.js": {
+ "version": "9.13.1",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz",
+ "integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A=="
+ },
+ "homedir-polyfill": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
+ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+ },
+ "interpret": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
+ },
+ "is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "requires": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "requires": {
+ "is-unc-path": "^1.0.0"
+ }
+ },
+ "is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "requires": {
+ "unc-path-regex": "^0.1.2"
+ }
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "jquery": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
+ "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
+ },
+ "jquery-form": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/jquery-form/-/jquery-form-4.2.2.tgz",
+ "integrity": "sha512-HJTef7DRBSg8ge/RNUw8rUTTtB3l8ozO0OhD16AzDl+eIXp4skgCqRTd9fYPsOzL+pN6+1B9wvbTLGjgikz8Tg==",
+ "requires": {
+ "jquery": ">=1.7.2"
+ }
+ },
+ "jquery-mousewheel": {
+ "version": "3.1.13",
+ "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz",
+ "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU="
+ },
+ "jquery-validation": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.18.0.tgz",
+ "integrity": "sha512-+MK0pvoegfLrJnwtCU6tx305Vgp9HWevpmdVwDf5TthmINkn0wqqLD0bpa75EERlHsBBjMmza//ppx5ZQPnW3Q==",
+ "requires": {
+ "jquery": "^1.7 || ^2.0 || ^3.1"
+ }
+ },
+ "jquery-validation-unobtrusive": {
+ "version": "3.2.11",
+ "resolved": "https://registry.npmjs.org/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-3.2.11.tgz",
+ "integrity": "sha512-3FQPllaWdD+Aq55zJLGSW39+eXPDz1HhwAvrSwYi8zHQ8DVcu5IJ1HVeTiCl0BnCnrIBvfFU3zEB/DrGdcoRIQ==",
+ "requires": {
+ "jquery": ">=1.8",
+ "jquery-validation": ">=1.16"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ },
+ "liftoff": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
+ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
+ "requires": {
+ "extend": "^3.0.0",
+ "findup-sync": "^2.0.0",
+ "fined": "^1.0.1",
+ "flagged-respawn": "^1.0.0",
+ "is-plain-object": "^2.0.4",
+ "object.map": "^1.0.0",
+ "rechoir": "^0.6.2",
+ "resolve": "^1.1.7"
+ }
+ },
+ "linkify-it": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
+ "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=",
+ "requires": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "lodash": {
+ "version": "1.0.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz",
+ "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE="
+ },
+ "lodash._basecopy": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY="
+ },
+ "lodash._basetostring": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
+ "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U="
+ },
+ "lodash._basevalues": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
+ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc="
+ },
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+ },
+ "lodash._isiterateecall": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw="
+ },
+ "lodash._reescape": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
+ "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo="
+ },
+ "lodash._reevaluate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
+ "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0="
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
+ },
+ "lodash._root": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
+ "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
+ },
+ "lodash.escape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
+ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
+ "requires": {
+ "lodash._root": "^3.0.0"
+ }
+ },
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
+ },
+ "lodash.keys": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+ "requires": {
+ "lodash._getnative": "^3.0.0",
+ "lodash.isarguments": "^3.0.0",
+ "lodash.isarray": "^3.0.0"
+ }
+ },
+ "lodash.restparam": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
+ "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU="
+ },
+ "lodash.template": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
+ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
+ "requires": {
+ "lodash._basecopy": "^3.0.0",
+ "lodash._basetostring": "^3.0.0",
+ "lodash._basevalues": "^3.0.0",
+ "lodash._isiterateecall": "^3.0.0",
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.escape": "^3.0.0",
+ "lodash.keys": "^3.0.0",
+ "lodash.restparam": "^3.0.0",
+ "lodash.templatesettings": "^3.0.0"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
+ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
+ "requires": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.escape": "^3.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
+ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
+ },
+ "make-iterator": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+ "requires": {
+ "kind-of": "^6.0.2"
+ }
+ },
+ "malihu-custom-scrollbar-plugin": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-3.1.5.tgz",
+ "integrity": "sha1-MQzsxeWUFaHCnp37XStuAdZqKe8=",
+ "requires": {
+ "jquery-mousewheel": ">=3.0.6"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "markdown-it": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
+ "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "entities": "~1.1.1",
+ "linkify-it": "^2.0.0",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ }
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
+ },
+ "merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "requires": {
+ "readable-stream": "^2.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "minimatch": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
+ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=",
+ "requires": {
+ "brace-expansion": "^1.0.0"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "multipipe": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
+ "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
+ "requires": {
+ "duplexer2": "0.0.2"
+ }
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "natives": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz",
+ "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA=="
+ },
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.defaults": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+ "requires": {
+ "array-each": "^1.0.1",
+ "array-slice": "^1.0.0",
+ "for-own": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+ "requires": {
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "once": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
+ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "orchestrator": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz",
+ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=",
+ "requires": {
+ "end-of-stream": "~0.1.5",
+ "sequencify": "~0.0.7",
+ "stream-consume": "~0.1.0"
+ }
+ },
+ "ordered-read-streams": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz",
+ "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY="
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+ },
+ "owl.carousel": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/owl.carousel/-/owl.carousel-2.3.4.tgz",
+ "integrity": "sha512-JaDss9+feAvEW8KZppPSpllfposEzQiW+Ytt/Xm5t/3CTJ7YVmkh6RkWixoA2yXk2boIwedYxOvrrppIGzru9A==",
+ "requires": {
+ "jquery": ">=1.8.3"
+ }
+ },
+ "pako": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.3.tgz",
+ "integrity": "sha1-X1FbDGci4ZgpIK6ABerLC3ynPM8="
+ },
+ "parse-filepath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+ "requires": {
+ "is-absolute": "^1.0.0",
+ "map-cache": "^0.2.0",
+ "path-root": "^0.1.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "path": {
+ "version": "0.12.7",
+ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+ "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
+ "requires": {
+ "process": "^0.11.1",
+ "util": "^0.10.3"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+ },
+ "path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+ "requires": {
+ "path-root-regex": "^0.1.0"
+ }
+ },
+ "path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0="
+ },
+ "plantuml-encoder": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.2.5.tgz",
+ "integrity": "sha512-viV7Sz+BJNX/sC3iyebh2VfLyAZKuu3+JuBs2ISms8+zoTGwPqwk3/WEDw/zROmGAJ/xD4sNd8zsBw/YmTo7ng==",
+ "requires": {
+ "pako": "1.0.3",
+ "utf8-bytes": "0.0.1"
+ }
+ },
+ "popper.js": {
+ "version": "1.14.6",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.6.tgz",
+ "integrity": "sha512-AGwHGQBKumlk/MDfrSOf0JHhJCImdDMcGNoqKmKkU+68GFazv3CQ6q9r7Ja1sKDZmYWTckY/uLyEznheTDycnA=="
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
+ },
+ "pretty-hrtime": {
+ "version": "1.0.3",
+ "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
+ },
+ "prismjs": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.15.0.tgz",
+ "integrity": "sha512-Lf2JrFYx8FanHrjoV5oL8YHCclLQgbJcVZR+gikGGMqz6ub5QVWDTM6YIwm3BuPxM/LOV+rKns3LssXNLIf+DA==",
+ "requires": {
+ "clipboard": "^2.0.0"
+ }
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+ },
+ "promise-polyfill": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz",
+ "integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc="
+ },
+ "raphael": {
+ "version": "git+https://github.com/nhnent/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
+ "from": "git+https://github.com/nhnent/raphael.git#2.2.0-c",
+ "requires": {
+ "eve": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1"
+ }
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "requires": {
+ "resolve": "^1.1.6"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.10.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
+ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+ },
+ "replace-ext": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ="
+ },
+ "resize-observer-polyfill": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz",
+ "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg=="
+ },
+ "resolve": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+ "requires": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "requires": {
+ "glob": "^7.0.5"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "select": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+ "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
+ },
+ "select2": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.5.tgz",
+ "integrity": "sha1-eqxQaSVhmFs007guxV4ib4lg1Ao=",
+ "requires": {
+ "almond": "~0.3.1",
+ "jquery-mousewheel": "~3.1.13"
+ }
+ },
+ "semver": {
+ "version": "4.3.6",
+ "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+ "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
+ },
+ "sequencify": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz",
+ "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw="
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "sigmund": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
+ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
+ },
+ "sparkles": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+ "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw=="
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "squire-rte": {
+ "version": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd",
+ "from": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd"
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "stream-consume": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz",
+ "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg=="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz",
+ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=",
+ "requires": {
+ "first-chunk-stream": "^1.0.0",
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ },
+ "sweetalert": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.0.tgz",
+ "integrity": "sha512-9YKj0SvjKyBfRWco50UOsIbXVeifYbxzT9Qda7EsqC01eafHGCSG0IR7g942ufjzt7lnwO8ZZBwr6emXv2fQrg==",
+ "requires": {
+ "es6-object-assign": "^1.1.0",
+ "promise-polyfill": "^6.0.2"
+ }
+ },
+ "through2": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+ "requires": {
+ "readable-stream": "^2.1.5",
+ "xtend": "~4.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "tildify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz",
+ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=",
+ "requires": {
+ "os-homedir": "^1.0.0"
+ }
+ },
+ "time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM="
+ },
+ "timeago": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/timeago/-/timeago-1.6.3.tgz",
+ "integrity": "sha512-x97d1X1KsNapWJTgCOOAy/59XagYu2WsDTAH/yvPsWi5bqtGbLPaVZBv3HZ3jTpakHR+JGGyrI9qC0yuvIAvnQ==",
+ "requires": {
+ "jquery": ">=1.2.3"
+ }
+ },
+ "tiny-emitter": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz",
+ "integrity": "sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow=="
+ },
+ "to-mark": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/to-mark/-/to-mark-1.1.3.tgz",
+ "integrity": "sha512-Wai0j2IPk5vEsuPHgTBjK/xzGwUAmddUbUVLZgAvOiTZKEJwmVHRdEHO3yTta4LxgY4W9761sP1MkAZbYVXcig=="
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "toastr": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
+ "integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=",
+ "requires": {
+ "jquery": ">=1.12.0"
+ }
+ },
+ "tui-chart": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/tui-chart/-/tui-chart-3.4.0.tgz",
+ "integrity": "sha512-gPIJ1SsPhISj/SlzysA9fkLJMlnPV1PLaUE+gxUioZaDtfoZ+TxSE+Vs1rOvoXUUmT/v5+qlH2iM2fkaLvDU0A==",
+ "requires": {
+ "babel-polyfill": "^6.26.0",
+ "raphael": "git+https://github.com/nhnent/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
+ "tui-code-snippet": "^1.4.0"
+ }
+ },
+ "tui-code-snippet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/tui-code-snippet/-/tui-code-snippet-1.4.0.tgz",
+ "integrity": "sha512-a7XzHRbRDi6Tt4lGcopq6ctQjVrzmnw9JMoTFqur5gczgtw5tmgUqXHjg8D9IonDkzZNq5gYLhkzykx4fmn+GA=="
+ },
+ "tui-color-picker": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tui-color-picker/-/tui-color-picker-2.2.0.tgz",
+ "integrity": "sha512-oAzMxF19bDExbvv7jVWQBPlrJ8sO3jQe+1rHqKkM4FtpvtGNlJO/ty19LW6pk9CCi1y43cgoG3QUt41ctGmygQ==",
+ "requires": {
+ "tui-code-snippet": "^1.3.0"
+ }
+ },
+ "tui-editor": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/tui-editor/-/tui-editor-1.2.6.tgz",
+ "integrity": "sha512-sVvs8yx3G1a/+YbR4VxzzfHFxPIPgattai+RDAHaUYeDkRhFPi3LeKN8A89jPyvUhyM8NhZWlhVd8ZTYx9ykNg==",
+ "requires": {
+ "codemirror": "^5.33.0",
+ "highlight.js": "^9.12.0",
+ "jquery": "^3.3.1",
+ "markdown-it": "^8.4.0",
+ "plantuml-encoder": "^1.2.5",
+ "resize-observer-polyfill": "^1.5.0",
+ "squire-rte": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd",
+ "to-mark": "^1.1.2",
+ "tui-chart": "^3.0.1",
+ "tui-code-snippet": "^1.3.0",
+ "tui-color-picker": "^2.2.0"
+ }
+ },
+ "uc.micro": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
+ "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg=="
+ },
+ "unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "unique-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz",
+ "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs="
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ }
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
+ },
+ "user-home": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA="
+ },
+ "utf8-bytes": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz",
+ "integrity": "sha1-EWsCVEjJtQAIHN+/H01sbDfYg30="
+ },
+ "util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "v8flags": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz",
+ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
+ "requires": {
+ "user-home": "^1.1.1"
+ }
+ },
+ "vinyl": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
+ "requires": {
+ "clone": "^1.0.0",
+ "clone-stats": "^0.0.1",
+ "replace-ext": "0.0.1"
+ }
+ },
+ "vinyl-fs": {
+ "version": "0.3.14",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz",
+ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=",
+ "requires": {
+ "defaults": "^1.0.0",
+ "glob-stream": "^3.1.5",
+ "glob-watcher": "^0.0.6",
+ "graceful-fs": "^3.0.0",
+ "mkdirp": "^0.5.0",
+ "strip-bom": "^1.0.0",
+ "through2": "^0.6.1",
+ "vinyl": "^0.4.0"
+ },
+ "dependencies": {
+ "clone": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
+ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8="
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ },
+ "vinyl": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
+ "requires": {
+ "clone": "^0.2.0",
+ "clone-stats": "^0.0.1"
+ }
+ }
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+ }
+ }
+}
diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css
index 36bfe30a55..ad4f5adca0 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css
+++ b/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 {
diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
index b8f9189bf2..524731f0ff 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
+++ b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
@@ -1 +1 @@
-body{position:relative;font-family:'PT Sans',sans-serif;background:url(../assets/tools/bg.jpg) center center no-repeat;background-attachment:fixed;}h1,h2,h3,h4,h5,h6{font-family:'PT Sans Caption',sans-serif;}h1{font-size:2.25em;margin:1.5rem 0 .75rem;}h2{font-size:1.75em;margin:1.5rem 0 .75rem;}h3{font-size:1.5em;margin:1.5rem 0 .75rem;}h4{font-size:1.25em;margin:1.5rem 0 .75rem;}h5{font-size:1em;margin:1.5rem 0 .75rem;}h6{font-size:1em;margin:1.5rem 0 .75rem;}img{max-width:100%;}.navbar{padding:1.75rem 2rem;}.nav-link{padding-left:1rem !important;padding-right:1rem !important;}.navbar-dark .navbar-nav .nav-link{color:#fff;}.text-success{color:#e90052 !important;}a.text-success:hover,a.text-success:focus{color:#e90052 !important;}.bg-success,.btn-success,.badge-success{background-color:#e90052 !important;border-color:#e90052 !important;}.bg-success{background-color:rgba(233,0,82,.8) !important;}.bg-blue,.btn-blue,.badge-blue{background-color:#03abed !important;border-color:#03abed !important;color:#fff;}.bg-blue:hover,.btn-blue:hover,.badge-blue:hover{background-color:#0095d0 !important;border-color:#0095d0 !important;color:#fff !important;}.btn:focus,.btn:active,.btn:visited,a:focus,a:active,a:visited{outline:none !important;box-shadow:none;}.text-primary{color:#38003c !important;}.bg-primary,.btn-primary,.badge-primary{background-color:#38003c !important;border-color:#38003c !important;}.bg-primary{background-color:rgba(56,0,60,.9) !important;}.btn-outline-primary{color:#38003c !important;border-color:#38003c !important;}.btn-outline-primary:hover{background-color:#38003c !important;color:#fff !important;}.dropdown-menu{padding:1rem 0;border-radius:.15rem;border:none;box-shadow:5px 5px 40px rgba(0,0,0,.3);}.dropdown-menu .dropdown-item{padding:.75rem 1.5rem;}#index-video{position:fixed;right:0;bottom:0;min-width:100%;min-height:100%;z-index:-1;}.bg-gradient-horizontal{background:#fff;}@media(min-width:480px){.bg-gradient-horizontal{background:#fff;background:-moz-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:-webkit-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:linear-gradient(to right,#fff 50%,#f2f2f2 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#f2f2f2',GradientType=1);}}.bg-transparency{background:rgba(255,255,255,.9);}.bg-light{background:#eee;}.for-mobile{display:none;}.for-desktop{display:inline-block;}.breadcrumb{background:none;font-size:.85em;border-radius:0;border-bottom:1px solid #f5f5f5;margin:0 -15px;padding:.5rem 0;text-align:center;display:block;}.breadcrumb .breadcrumb-item+.breadcrumb-item{padding-left:.2rem;}.breadcrumb .breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.4rem;color:#eee;content:"|";}.breadcrumb .breadcrumb-item{color:#eee;display:inline-block;}.breadcrumb .breadcrumb-item a{color:#aaa;}.close{font-weight:300;}hr{margin-top:2rem;margin-bottom:2.5rem;border-top:1px solid rgba(0,0,0,.05);}span.with-br-name{font-size:.75em;}span.br-name{display:block;font-size:1.25em;}span.br-name-1{display:block;font-size:1em;}.btn-fifty{display:flex;}.btn-fifty .btn{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;}.p-responsive{padding:120px 0;}.global-header{display:none;}.global-header .navbar{background:rgba(255,255,255,.2);}.global-header .navbar .products-link{border:1px solid rgba(255,255,255,.75);border-radius:.2rem;margin:0 10px;padding-top:.36rem;padding-bottom:.36rem;}.global-header .navbar .search-item{position:relative;}.global-header .navbar .search-item input.form-control{background:none;border:1px solid rgba(255,255,255,.25);border-radius:.2rem;color:#fff;padding-left:2.5rem;min-width:280px;}.global-header .navbar .search-item input.form-control::-webkit-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control::-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-ms-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item .btn-search{position:absolute;top:-2px;left:-1px;background:none;}header .btn{background:#fff;}header .btn.btn-login,header .btn.btn-logout{border:2px solid #fff;color:#fff;background:transparent;margin-right:6px;}header .btn.btn-login:hover,header .btn.btn-logout:hover{background:#fff;color:#e90052;}.product-header{font-size:1.1rem;}.product-header .navbar-brand{font-size:1.75rem;}.home-logo{width:120px;}.jumbotron-logo{width:240px;margin-bottom:40px;}.forkme{position:fixed;bottom:0;right:0;}.footer-logo{width:140px;}.jumbotron{background:#006bf0;background:-moz-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:-webkit-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:linear-gradient(to right,rgba(56,0,60,.9) 0%,rgba(185,0,74,.78) 100%);margin-top:-120px;border-radius:0;margin-bottom:0;height:90vh;}.jumbotron.jumbocover{padding:120px 0 20px;height:auto;}.jumbotron>.row{height:calc(90vh - 120px);}.jumbotron .abp-version{position:absolute;font-size:11px;right:1px;top:-2px;padding:1px 4px 0;display:inline-block;color:#fff;background:rgba(233,3,82,.7);border-radius:3px;opacity:.8;}.jumbotron .desc-span{font-size:1.4em;font-style:italic;opacity:.7;}.section-with-logos img{margin:25px;max-height:50px;transition:.4s;opacity:.6;-webkit-filter:grayscale(60%);filter:grayscale(60%);}.section-with-logos img:hover{opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}img.subsection-icon{width:64px;height:64px;}.toggle-row{display:none;}.btn-toggle .lessText{display:none;}.btn-toggle .moreText{display:block;}.btn-toggle.less .lessText{display:block;}.btn-toggle.less .moreText{display:none;}.abp-browser{margin:3rem 0 1rem;text-align:left;border-radius:6px;overflow:hidden;}.abp-browser .browser-container{border:1px solid #eee;}.abp-browser .browser-row{padding:4px 10px;background:#e5e5e5;}.abp-browser .browser-row:after{content:"";display:table;clear:both;}.abp-browser .browser-dot{margin-top:2px;margin-right:2px;height:12px;width:12px;background-color:#bbb;border-radius:50%;display:inline-block;}.abp-browser .abp-browser input[type=text]{width:100%;border-radius:3px;border:none;background-color:#fff;margin-top:-8px;height:25px;color:#666;padding:5px;}.abp-browser .browser-bar{width:17px;height:3px;background-color:#aaa;margin:3px 0;display:block;}.abp-browser .browser-content{padding:2rem;background:#f5f5f5;}.abp-browser .bg-primary,.abp-browser .btn-primary,.abp-browser .badge-primary{background-color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary{color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary:hover{background-color:#007bff !important;color:#fff !important;}span.code-arrow{padding:52px 0 18px;display:block;font-size:40px;}.docs-page{background:#f5f7f9;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1.5rem;position:relative;width:270px;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;top:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:calc(100vh - 190px);overflow:hidden;overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1.25rem 1.5rem;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search input.form-control{background:none;border-radius:.2rem;padding-left:2.5rem;width:100%;background:#eeeff2;border:0;font-size:.85em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{position:absolute;top:-5px;left:22px;background:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.913em;list-style:none;padding:0 0 0 20px;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label{margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle{transition:.3s;display:inline-block;width:18px;height:18px;text-align:center;padding:0;line-height:normal;border-radius:50%;margin-right:4px;position:absolute;left:0;top:8px;cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle img{width:14px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle:not(.last-link).opened{transform:rotate(180deg);}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#101010;font-weight:700;padding:7px 0;display:block;border-bottom:1px solid #eeeff3;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li label.tree-toggle{top:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#38003c;font-weight:bold;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:130px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;font-size:1.2rem;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content .docs-text-field{padding:3rem;}.docs-page .docs-page-index{position:relative;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;max-width:270px;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.95em;margin-left:18px;border-left:1px solid #e5e5e5;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:.2rem 0 .2rem 1rem;color:#aaa;line-height:1.1;position:relative;border-left:3px solid transparent;border-radius:0;margin-left:-2px;margin-top:2px;margin-bottom:2px;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{background:none;color:#38003b;border-color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors>.navbar{margin-left:-18px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .docs-inner-anchors .inner-title{padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:underline;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1200px){.container{max-width:1180px;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;height:calc(100vh - 72px);overflow:hidden;overflow-y:auto;position:fixed;top:72px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{top:-14px;left:-2px;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;display:block;margin-right:0;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}@media(max-width:767px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.jumbotron .btn,footer .btn{display:block;margin-bottom:10px;}.multi-tenancy{text-align:center !important;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}.jumbotron{padding-top:160px;margin-top:-160px;border-radius:0;padding-bottom:40px;margin-bottom:0;font-size:.85em;padding-left:45px;padding-right:45px;}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}.jumbotron{height:calc(100vh + 120px);}.jumbotron.jumbocover{height:auto;padding:160px 0 20px;}.jumbotron hr{display:none;}.jumbotron .btn{margin-bottom:0 !important;}.jumbotron .jumbotron-logo{margin-bottom:0;width:180px;height:62px;margin-top:-30px;}.jumbotron .jlogo-wrapper{height:62px;}}.vs-blog{margin-top:-88px !important;}.abp-account-container{max-width:400px;margin:0 auto;margin-top:-88px !important;}body{background-size:cover;}
\ No newline at end of file
+body{position:relative;font-family:'PT Sans',sans-serif;background:url(../assets/tools/bg.jpg) center center no-repeat;background-attachment:fixed;}h1,h2,h3,h4,h5,h6{font-family:'PT Sans Caption',sans-serif;}h1{font-size:2.25em;margin:1.5rem 0 .75rem;}h2{font-size:1.75em;margin:1.5rem 0 .75rem;}h3{font-size:1.5em;margin:1.5rem 0 .75rem;}h4{font-size:1.25em;margin:1.5rem 0 .75rem;}h5{font-size:1em;margin:1.5rem 0 .75rem;}h6{font-size:1em;margin:1.5rem 0 .75rem;}img{max-width:100%;}.navbar{padding:1.75rem 2rem;}.nav-link{padding-left:1rem !important;padding-right:1rem !important;}.navbar-dark .navbar-nav .nav-link{color:#fff;}.text-success{color:#e90052 !important;}a.text-success:hover,a.text-success:focus{color:#e90052 !important;}.bg-success,.btn-success,.badge-success{background-color:#e90052 !important;border-color:#e90052 !important;}.bg-success{background-color:rgba(233,0,82,.8) !important;}.bg-blue,.btn-blue,.badge-blue{background-color:#03abed !important;border-color:#03abed !important;color:#fff;}.bg-blue:hover,.btn-blue:hover,.badge-blue:hover{background-color:#0095d0 !important;border-color:#0095d0 !important;color:#fff !important;}.btn:focus,.btn:active,.btn:visited,a:focus,a:active,a:visited{outline:none !important;box-shadow:none;}.text-primary{color:#38003c !important;}.bg-primary,.btn-primary,.badge-primary{background-color:#38003c !important;border-color:#38003c !important;}.bg-primary{background-color:rgba(56,0,60,.9) !important;}.btn-outline-primary{color:#38003c !important;border-color:#38003c !important;}.btn-outline-primary:hover{background-color:#38003c !important;color:#fff !important;}.dropdown-menu{padding:1rem 0;border-radius:.15rem;border:none;box-shadow:5px 5px 40px rgba(0,0,0,.3);}.dropdown-menu .dropdown-item{padding:.75rem 1.5rem;}#index-video{position:fixed;right:0;bottom:0;min-width:100%;min-height:100%;z-index:-1;}.bg-gradient-horizontal{background:#fff;}@media(min-width:480px){.bg-gradient-horizontal{background:#fff;background:-moz-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:-webkit-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:linear-gradient(to right,#fff 50%,#f2f2f2 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#f2f2f2',GradientType=1);}}.bg-transparency{background:rgba(255,255,255,.9);}.bg-light{background:#eee;}.for-mobile{display:none;}.for-desktop{display:inline-block;}.breadcrumb{background:none;font-size:.85em;border-radius:0;border-bottom:1px solid #f5f5f5;margin:0 -15px;padding:.5rem 0;text-align:center;display:block;}.breadcrumb .breadcrumb-item+.breadcrumb-item{padding-left:.2rem;}.breadcrumb .breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.4rem;color:#eee;content:"|";}.breadcrumb .breadcrumb-item{color:#eee;display:inline-block;}.breadcrumb .breadcrumb-item a{color:#aaa;}.close{font-weight:300;}hr{margin-top:2rem;margin-bottom:2.5rem;border-top:1px solid rgba(0,0,0,.05);}span.with-br-name{font-size:.75em;}span.br-name{display:block;font-size:1.25em;}span.br-name-1{display:block;font-size:1em;}.btn-fifty{display:flex;}.btn-fifty .btn{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;}.p-responsive{padding:120px 0;}.global-header{display:none;}.global-header .navbar{background:rgba(255,255,255,.2);}.global-header .navbar .products-link{border:1px solid rgba(255,255,255,.75);border-radius:.2rem;margin:0 10px;padding-top:.36rem;padding-bottom:.36rem;}.global-header .navbar .search-item{position:relative;}.global-header .navbar .search-item input.form-control{background:none;border:1px solid rgba(255,255,255,.25);border-radius:.2rem;color:#fff;padding-left:2.5rem;min-width:280px;}.global-header .navbar .search-item input.form-control::-webkit-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control::-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-ms-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item .btn-search{position:absolute;top:-2px;left:-1px;background:none;}header .btn{background:#fff;}header .btn.btn-login,header .btn.btn-logout{border:2px solid #fff;color:#fff;background:transparent;margin-right:6px;}header .btn.btn-login:hover,header .btn.btn-logout:hover{background:#fff;color:#e90052;}.product-header{font-size:1.1rem;}.product-header .navbar-brand{font-size:1.75rem;}.home-logo{width:120px;}.jumbotron-logo{width:240px;margin-bottom:40px;}.forkme{position:fixed;bottom:0;right:0;}.footer-logo{width:140px;}.jumbotron{background:#006bf0;background:-moz-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:-webkit-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:linear-gradient(to right,rgba(56,0,60,.9) 0%,rgba(185,0,74,.78) 100%);margin-top:-120px;border-radius:0;margin-bottom:0;height:90vh;}.jumbotron.jumbocover{padding:120px 0 20px;height:auto;}.jumbotron>.row{height:calc(90vh - 120px);}.jumbotron .abp-version{position:absolute;font-size:11px;right:1px;top:-2px;padding:1px 4px 0;display:inline-block;color:#fff;background:rgba(233,3,82,.7);border-radius:3px;opacity:.8;}.jumbotron .desc-span{font-size:1.4em;font-style:italic;opacity:.7;}.section-with-logos img{margin:25px;max-height:50px;transition:.4s;opacity:.6;-webkit-filter:grayscale(60%);filter:grayscale(60%);}.section-with-logos img:hover{opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}img.subsection-icon{width:64px;height:64px;}.toggle-row{display:none;}.btn-toggle .lessText{display:none;}.btn-toggle .moreText{display:block;}.btn-toggle.less .lessText{display:block;}.btn-toggle.less .moreText{display:none;}.abp-browser{margin:3rem 0 1rem;text-align:left;border-radius:6px;overflow:hidden;}.abp-browser .browser-container{border:1px solid #eee;}.abp-browser .browser-row{padding:4px 10px;background:#e5e5e5;}.abp-browser .browser-row:after{content:"";display:table;clear:both;}.abp-browser .browser-dot{margin-top:2px;margin-right:2px;height:12px;width:12px;background-color:#bbb;border-radius:50%;display:inline-block;}.abp-browser .abp-browser input[type=text]{width:100%;border-radius:3px;border:none;background-color:#fff;margin-top:-8px;height:25px;color:#666;padding:5px;}.abp-browser .browser-bar{width:17px;height:3px;background-color:#aaa;margin:3px 0;display:block;}.abp-browser .browser-content{padding:2rem;background:#f5f5f5;}.abp-browser .bg-primary,.abp-browser .btn-primary,.abp-browser .badge-primary{background-color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary{color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary:hover{background-color:#007bff !important;color:#fff !important;}span.code-arrow{padding:52px 0 18px;display:block;font-size:40px;}.docs-page{background:#f5f7f9;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1.5rem;position:relative;width:270px;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;top:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:calc(100vh - 190px);overflow:hidden;overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1.25rem 1.5rem;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search input.form-control{background:none;border-radius:.2rem;padding-left:2.5rem;width:100%;background:#eeeff2;border:0;font-size:.85em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{position:absolute;top:-5px;left:22px;background:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.913em;list-style:none;padding:0 0 0 20px;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label{margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle{transition:.3s;display:inline-block;width:18px;height:18px;text-align:center;padding:0;line-height:normal;border-radius:50%;margin-right:4px;position:absolute;left:0;top:8px;cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle img{width:14px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle:not(.last-link).opened{transform:rotate(180deg);}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#101010;font-weight:700;padding:7px 0;display:block;border-bottom:1px solid #eeeff3;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li label.tree-toggle{top:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#38003c;font-weight:bold;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:130px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;font-size:1.2rem;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content .docs-text-field{padding:3rem;}.docs-page .docs-page-index{position:relative;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;max-width:270px;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.95em;margin-left:18px;border-left:1px solid #e5e5e5;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:.2rem 0 .2rem 1rem;color:#aaa;line-height:1.1;position:relative;border-left:3px solid transparent;border-radius:0;margin-left:-2px;margin-top:2px;margin-bottom:2px;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{background:none;color:#38003b;border-color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors>.navbar{margin-left:-18px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .docs-inner-anchors .inner-title{padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:underline;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1200px){.container{max-width:1180px;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;height:calc(100vh - 72px);overflow:hidden;overflow-y:auto;position:fixed;top:72px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{top:-14px;left:-2px;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;display:block;margin-right:0;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}@media(max-width:992px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.jumbotron .btn,footer .btn{display:block;margin-bottom:10px;}.multi-tenancy{text-align:center !important;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}.jumbotron{padding-top:160px;margin-top:-160px;border-radius:0;padding-bottom:40px;margin-bottom:0;font-size:.85em;padding-left:45px;padding-right:45px;}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}.jumbotron{height:calc(100vh + 120px);}.jumbotron.jumbocover{height:auto;padding:160px 0 20px;}.jumbotron hr{display:none;}.jumbotron .btn{margin-bottom:0 !important;}.jumbotron .jumbotron-logo{margin-bottom:0;width:180px;height:62px;margin-top:-30px;}.jumbotron .jlogo-wrapper{height:62px;}}.vs-blog{margin-top:-88px !important;}.abp-account-container{max-width:400px;margin:0 auto;margin-top:-88px !important;}body{background-size:cover;}
\ No newline at end of file
diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss
index 07bfa1b354..4d9cb4a995 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss
+++ b/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";
}
diff --git a/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj b/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj
index f445e989d1..254d8b65c5 100644
--- a/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj
+++ b/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj
@@ -15,9 +15,9 @@
-
+
-
+
diff --git a/build-all.ps1 b/build-all.ps1
index 935cfeb8a9..5d800ebdf9 100644
--- a/build-all.ps1
+++ b/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
}
}
diff --git a/common.DotSettings b/common.DotSettings
new file mode 100644
index 0000000000..cb0b2c919f
--- /dev/null
+++ b/common.DotSettings
@@ -0,0 +1,23 @@
+
+ True
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ Required
+ Required
+ Required
+ Required
+ False
+ True
+ False
+ False
+ True
+ False
+ False
+ SQL
+
\ No newline at end of file
diff --git a/common.props b/common.props
index 15df803252..040172c6d4 100644
--- a/common.props
+++ b/common.props
@@ -1,7 +1,7 @@
latest
- 0.9.0
+ 0.13.0
$(NoWarn);CS1591
https://abp.io/assets/abp_nupkg.png
https://abp.io
@@ -11,7 +11,7 @@
-
+
\ No newline at end of file
diff --git a/docs/en/AspNetCore/Auto-API-Controllers.md b/docs/en/AspNetCore/Auto-API-Controllers.md
new file mode 100644
index 0000000000..48567b6919
--- /dev/null
+++ b/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(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/).
+
+
+
+### 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(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(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.
\ No newline at end of file
diff --git a/docs/en/AspNetCore/Bundling-Minification.md b/docs/en/AspNetCore/Bundling-Minification.md
index b8d70d8624..7170690ef3 100644
--- a/docs/en/AspNetCore/Bundling-Minification.md
+++ b/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(options =>
@@ -200,8 +199,9 @@ services.Configure(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
@@ -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(options =>
+{
+ options
+ .Extensions()
+ .Add();
+});
+````
+
+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(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)
diff --git a/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md b/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
new file mode 100644
index 0000000000..0b0667dd0d
--- /dev/null
+++ b/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> 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` for a more explicit usage. In this case you will use the `Service` property of the `IHttpClientProxy` 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(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` interface to use the client proxies (see the related section above).
\ No newline at end of file
diff --git a/docs/en/Autofac-Integration.md b/docs/en/Autofac-Integration.md
new file mode 100644
index 0000000000..b3aced3e94
--- /dev/null
+++ b/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(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(options =>
+ {
+ options.UseAutofac(); //Autofac integration
+ }))
+ {
+ //...
+ }
+ }
+ }
+}
+````
+
diff --git a/docs/en/Best-Practices/MongoDB-Integration.md b/docs/en/Best-Practices/MongoDB-Integration.md
index 32eefadd6a..76b6e8561f 100644
--- a/docs/en/Best-Practices/MongoDB-Integration.md
+++ b/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(map =>
- {
- map.AutoMap();
- map.ConfigureExtraProperties();
- });
-
- BsonClassMap.RegisterClassMap(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` 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(options =>
{
options.AddRepository();
diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md
index a001d52ec9..d1ca14950c 100644
--- a/docs/en/Dependency-Injection.md
+++ b/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(new TaxCalculator(taxRatio: 0.18));
//Register a factory method that resolves from IServiceProvider
- context.Services.AddScoped(sp => sp.GetRequiredService());
+ context.Services.AddScoped(
+ sp => sp.GetRequiredService()
+ );
}
}
````
-### 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();
+ }
+ });
+ }
+}
+````
+
+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)
diff --git a/docs/en/Dynamic-Proxying-Interceptors.md b/docs/en/Dynamic-Proxying-Interceptors.md
new file mode 100644
index 0000000000..76a23daa8f
--- /dev/null
+++ b/docs/en/Dynamic-Proxying-Interceptors.md
@@ -0,0 +1,3 @@
+## Dynamic Proxying / Interceptors
+
+TODO
\ No newline at end of file
diff --git a/docs/en/Entities.md b/docs/en/Entities.md
index 89688d58c8..a90b95d100 100644
--- a/docs/en/Entities.md
+++ b/docs/en/Entities.md
@@ -41,7 +41,7 @@ public class UserRole : Entity
public DateTime CreationTime { get; set; }
- public Phone()
+ public UserRole()
{
}
diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md
index 4f9ff367ee..e608736bcd 100644
--- a/docs/en/Entity-Framework-Core.md
+++ b/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` 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
+{
+
+}
+```
+
+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,
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` 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(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,
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:
diff --git a/docs/en/Event-Bus.md b/docs/en/Event-Bus.md
new file mode 100644
index 0000000000..cf2b57c018
--- /dev/null
+++ b/docs/en/Event-Bus.md
@@ -0,0 +1,3 @@
+# Event Bus
+
+TODO
\ No newline at end of file
diff --git a/docs/en/Getting-Started-AspNetCore-Application.md b/docs/en/Getting-Started-AspNetCore-Application.md
index f242f8cd46..fe1ff3450b 100644
--- a/docs/en/Getting-Started-AspNetCore-Application.md
+++ b/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(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).
diff --git a/docs/en/Getting-Started-AspNetCore-MVC-Template.md b/docs/en/Getting-Started-AspNetCore-MVC-Template.md
index 665cec98b1..de9a5b09cb 100644
--- a/docs/en/Getting-Started-AspNetCore-MVC-Template.md
+++ b/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:
diff --git a/docs/en/Getting-Started-Console-Application.md b/docs/en/Getting-Started-Console-Application.md
index 00c3d1e0a2..faaa8cd376 100644
--- a/docs/en/Getting-Started-Console-Application.md
+++ b/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:

-### 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(options =>
+ {
+ options.UseAutofac(); //Autofac integration
+ }))
+ {
+ application.Initialize();
+
+ //Resolve a service and use it
+ var helloWorldService =
+ application.ServiceProvider.GetService();
+ 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).
diff --git a/docs/en/Index.md b/docs/en/Index.md
index 443579e40e..b1bccab0ea 100644
--- a/docs/en/Index.md
+++ b/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.
diff --git a/docs/en/Localization.md b/docs/en/Localization.md
index b6d27cc9ce..d34dc8232a 100644
--- a/docs/en/Localization.md
+++ b/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(options =>
- {
+ {
+ //Define a new localization resource (TestResource)
options.Resources
.Add("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(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(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 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.
diff --git a/docs/en/Microservice-Architecture.md b/docs/en/Microservice-Architecture.md
new file mode 100644
index 0000000000..e30c070a01
--- /dev/null
+++ b/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.
\ No newline at end of file
diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md
index 6e1c724669..6a0561a0c5 100644
--- a/docs/en/Module-Development-Basics.md
+++ b/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).
\ No newline at end of file
diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md
new file mode 100644
index 0000000000..1aa81621f5
--- /dev/null
+++ b/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.
+
+
+
+### 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**.
+
+
+
+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
+
+ ```
+* [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
+
+ ```
+* [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
+
+ ```
+* [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
+
+ ```
+
+
+
+### 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(options =>
+ {
+ options.DefinitionProviders.Add();
+ });
+
+ Configure(options =>
+ {
+ options.AddProfile();
+ });
+ }
+ }
+ ```
+
+
+* 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
+ {
+ public MyProjectDbContext(DbContextOptions 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>();
+
+ 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: `` (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: `` (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: ``
+
+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 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`.
+
+
+
+
+
+Finally a new Docs Module is added to your project which is feeded with GitHub.
\ No newline at end of file
diff --git a/docs/en/Modules/Index.md b/docs/en/Modules/Index.md
new file mode 100644
index 0000000000..9dc5da7a99
--- /dev/null
+++ b/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.
\ No newline at end of file
diff --git a/docs/en/MongoDB.md b/docs/en/MongoDB.md
index c03c6f4f2c..e7d8084f41 100644
--- a/docs/en/MongoDB.md
+++ b/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(b =>
- {
- b.CollectionName = "Questions";
- });
+ base.CreateModel(modelBuilder);
+
+ //Customize the configuration for your collections.
}
}
```
* It's derived from `AbpMongoDbContext` class.
* Adds a public `IMongoCollection` 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` 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(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 Questions => Collection();
+````
+
+### 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` 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(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:
diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md
new file mode 100644
index 0000000000..747c733683
--- /dev/null
+++ b/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:
+
+
+
+### 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
+
+...
\ No newline at end of file
diff --git a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
index 9a48022e27..6db6766c0b 100644
--- a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
+++ b/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
-{
- public DbSet Book { get; set; }
- ...
-}
+ public class BookStoreDbContext : AbpDbContext
+ {
+ public DbSet 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
diff --git a/docs/en/Virtual-File-System.md b/docs/en/Virtual-File-System.md
index 9a27f3c426..c89a2a34ef 100644
--- a/docs/en/Virtual-File-System.md
+++ b/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(options =>
{
- //ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project
- options.FileSets.ReplaceEmbeddedByPyhsical(
+ //ReplaceEmbeddedByPhysical gets the root folder of the MyModule project
+ options.FileSets.ReplaceEmbeddedByPhysical(
Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}MyModuleProject", Path.DirectorySeparatorChar))
);
});
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index fa8ec3552e..905821c73a 100644
--- a/docs/en/docs-nav.json
+++ b/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"
},
diff --git a/docs/en/images/bookstore-apis.png b/docs/en/images/bookstore-apis.png
new file mode 100644
index 0000000000..aedd79c7f1
Binary files /dev/null and b/docs/en/images/bookstore-apis.png differ
diff --git a/docs/en/images/docs-module_download-new-abp-project.png b/docs/en/images/docs-module_download-new-abp-project.png
new file mode 100644
index 0000000000..0da3b7a67a
Binary files /dev/null and b/docs/en/images/docs-module_download-new-abp-project.png differ
diff --git a/docs/en/images/docs-module_download-sample-navigation-menu.png b/docs/en/images/docs-module_download-sample-navigation-menu.png
new file mode 100644
index 0000000000..9a1232f198
Binary files /dev/null and b/docs/en/images/docs-module_download-sample-navigation-menu.png differ
diff --git a/docs/en/images/docs-module_solution-explorer.png b/docs/en/images/docs-module_solution-explorer.png
new file mode 100644
index 0000000000..cafc38f0b0
Binary files /dev/null and b/docs/en/images/docs-module_solution-explorer.png differ
diff --git a/docs/en/images/microservice-sample-diagram.png b/docs/en/images/microservice-sample-diagram.png
new file mode 100644
index 0000000000..b1d9f6c66e
Binary files /dev/null and b/docs/en/images/microservice-sample-diagram.png differ
diff --git a/docs/zh-Hans/AspNetCore/Auto-API-Controllers.md b/docs/zh-Hans/AspNetCore/Auto-API-Controllers.md
new file mode 100644
index 0000000000..afe8ea700b
--- /dev/null
+++ b/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(options =>
+ {
+ options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
+ });
+ }
+}
+````
+
+此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容.
+
+
+
+### 例子
+
+一些示例方法名称和按约定生成的相应路由:
+
+| 服务方法名称 | 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(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(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路径/路由的客户端使用.
\ No newline at end of file
diff --git a/docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md b/docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md
new file mode 100644
index 0000000000..f964ac9013
--- /dev/null
+++ b/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> 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`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy`接口的`Service`属性.
+
+## 配置
+
+### RemoteServiceOptions
+
+默认情况下`RemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如:
+
+````csharp
+public override void ConfigureServices(ServiceConfigurationContext context)
+{
+ context.Services.Configure(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`接口去使用客户端代理.(参见上面的相关章节).
\ No newline at end of file
diff --git a/docs/zh-Hans/Autofac-Integration.md b/docs/zh-Hans/Autofac-Integration.md
new file mode 100644
index 0000000000..9b1d249e4e
--- /dev/null
+++ b/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(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(options =>
+ {
+ options.UseAutofac(); //Autofac integration
+ }))
+ {
+ //...
+ }
+ }
+ }
+}
+````
+
diff --git a/docs/zh-Hans/Event-Bus.md b/docs/zh-Hans/Event-Bus.md
new file mode 100644
index 0000000000..0adb56101d
--- /dev/null
+++ b/docs/zh-Hans/Event-Bus.md
@@ -0,0 +1,3 @@
+# Event Bus
+
+ TODO
\ No newline at end of file
diff --git a/docs/zh-Hans/Microservice-Architecture.md b/docs/zh-Hans/Microservice-Architecture.md
new file mode 100644
index 0000000000..166591e779
--- /dev/null
+++ b/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框架的完整的微服务的解决方案.
\ No newline at end of file
diff --git a/docs/zh-Hans/Module-Development-Basics.md b/docs/zh-Hans/Module-Development-Basics.md
index 044016e17a..9feaa8c7f9 100644
--- a/docs/zh-Hans/Module-Development-Basics.md
+++ b/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).
diff --git a/docs/zh-Hans/Modules/Docs.md b/docs/zh-Hans/Modules/Docs.md
new file mode 100644
index 0000000000..cfe287082b
--- /dev/null
+++ b/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` 做为数据库提供者.
+
+
+
+### 2- 运行这个空项目
+
+下载项目后, 解压压缩文档并且打开 `Acme.MyProject.sln`. 你可以看到这个解决方案包含了 `Application`, `Domain `, `EntityFrameworkCore` 和 `Web` 项目. 右键选择 `Acme.MyProject.Web` 项目**设置为启动项目**.
+
+
+
+数据库连接字符串位于`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
+
+ ```
+* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) 需要安装到 `Acme.MyProject.EntityFrameworkCore` 项目.
+
+ - 修改 `Acme.MyProject.EntityFrameworkCore.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
+
+ ```csharp
+
+ ```
+* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) 需要安装到 `Acme.MyProject.Application` 项目.
+
+ * 修改 `Acme.MyProject.Application.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
+
+ ```csharp
+
+ ```
+* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/) 需要安装到 `Acme.MyProject.Web` 项目.
+
+ - 修改 `Acme.MyProject.Web.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
+
+ ```csharp
+
+ ```
+
+
+
+### 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(options =>
+ {
+ options.DefinitionProviders.Add();
+ });
+
+ Configure(options =>
+ {
+ options.AddProfile();
+ });
+ }
+ }
+ ```
+
+
+* 打开 `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
+ {
+ public MyProjectDbContext(DbContextOptions 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>();
+
+ 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: `` (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: `` (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: ``
+
+对于 `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 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` .
+
+
+
+最后,为您的项目添加了一个新的Docs模块, 该模块由GitHub提供.
\ No newline at end of file
diff --git a/docs/zh-Hans/Modules/Index.md b/docs/zh-Hans/Modules/Index.md
new file mode 100644
index 0000000000..8e5edf35b6
--- /dev/null
+++ b/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)获取所有模块的源代码.
\ No newline at end of file
diff --git a/docs/zh-Hans/Samples/Microservice-Demo.md b/docs/zh-Hans/Samples/Microservice-Demo.md
new file mode 100644
index 0000000000..eeac6e0749
--- /dev/null
+++ b/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/)**部署**和运行所有的服务和应用程序.
+
+下图显示了该系统:
+
+
+
+### 源码
+
+你可以从[GitHub仓库](https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo)获取源码.
+
+### 状态
+
+此示例仍处于开发阶段,尚未完成.
+
+## 微服务
+
+### 身份认证服务
+
+...
\ No newline at end of file
diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
index a9e333690f..34acc3f01f 100644
--- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
+++ b/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
diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
index 418c29a119..6b31e9ba84 100644
--- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
+++ b/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
\ No newline at end of file
+TODO
diff --git a/docs/zh-Hans/Virtual-File-System.md b/docs/zh-Hans/Virtual-File-System.md
index e25d7f61b4..05d8f59a85 100644
--- a/docs/zh-Hans/Virtual-File-System.md
+++ b/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(options =>
{
- //ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project
- options.FileSets.ReplaceEmbeddedByPyhsical(
+ //ReplaceEmbeddedByPhysical gets the root folder of the MyModule project
+ options.FileSets.ReplaceEmbeddedByPhysical(
Path.Combine(hostingEnvironment.ContentRootPath, "..\\MyModuleProject")
);
});
diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json
index 362e6fbc65..d9ac2aea60 100644
--- a/docs/zh-Hans/docs-nav.json
+++ b/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"
}
]
-}
\ No newline at end of file
+}
diff --git a/docs/zh-Hans/images/bookstore-apis.png b/docs/zh-Hans/images/bookstore-apis.png
new file mode 100644
index 0000000000..aedd79c7f1
Binary files /dev/null and b/docs/zh-Hans/images/bookstore-apis.png differ
diff --git a/docs/zh-Hans/images/docs-module_download-new-abp-project.png b/docs/zh-Hans/images/docs-module_download-new-abp-project.png
new file mode 100644
index 0000000000..0da3b7a67a
Binary files /dev/null and b/docs/zh-Hans/images/docs-module_download-new-abp-project.png differ
diff --git a/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png b/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png
new file mode 100644
index 0000000000..9a1232f198
Binary files /dev/null and b/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png differ
diff --git a/docs/zh-Hans/images/docs-module_solution-explorer.png b/docs/zh-Hans/images/docs-module_solution-explorer.png
new file mode 100644
index 0000000000..cafc38f0b0
Binary files /dev/null and b/docs/zh-Hans/images/docs-module_solution-explorer.png differ
diff --git a/docs/zh-Hans/images/microservice-sample-diagram.png b/docs/zh-Hans/images/microservice-sample-diagram.png
new file mode 100644
index 0000000000..b1d9f6c66e
Binary files /dev/null and b/docs/zh-Hans/images/microservice-sample-diagram.png differ
diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index d6518a0af3..08104ef769 100644
--- a/framework/Volo.Abp.sln
+++ b/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}
diff --git a/framework/Volo.Abp.sln.DotSettings b/framework/Volo.Abp.sln.DotSettings
index b8ca469cfe..b1de84b369 100644
--- a/framework/Volo.Abp.sln.DotSettings
+++ b/framework/Volo.Abp.sln.DotSettings
@@ -1,2 +1,8 @@
- SQL
\ No newline at end of file
+ SQL
+ True
+ D:\Github\abp\common.DotSettings
+ ..\..\common.DotSettings
+ True
+ 1
+
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
index 42b81370fd..722b6033ed 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs
index 7f00a58069..7ba8766dd8 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs
@@ -14,10 +14,10 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
Configure(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());
});
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs
similarity index 81%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs
index ebce890ea9..5b27a9d93c 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs
+++ b/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)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs
similarity index 87%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs
index 2894fcf0df..e342cb8f40 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs
+++ b/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://");
}
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs
similarity index 93%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs
index 58acdc493c..3f5e93bd36 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs
+++ b/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>()
+ .GetRequiredService>()
.LogWarning(text);
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs
index 51bdc57323..d2971063a5 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs
+++ b/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>()
+ .GetRequiredService>()
.LogWarning(e.ToString());
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs
similarity index 85%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs
index 88bd3bcc0d..9899e2613e 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs
+++ b/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)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs
similarity index 87%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs
index 10d4f1ebe1..3be155c68d 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs
+++ b/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)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs
index 8e6d3ae7ea..a162f1750e 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs
+++ b/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)
);
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
new file mode 100644
index 0000000000..911782697b
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.AspNetCore.Mvc.Client
+ Volo.Abp.AspNetCore.Mvc.Client
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
new file mode 100644
index 0000000000..3f1ed47435
--- /dev/null
+++ b/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
+ );
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
new file mode 100644
index 0000000000..f7df64b257
--- /dev/null
+++ b/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 Proxy { get; }
+ protected ICurrentUser CurrentUser { get; }
+ protected IDistributedCache Cache { get; }
+
+ public CachedApplicationConfigurationClient(
+ IDistributedCache cache,
+ IHttpClientProxy proxy,
+ ICurrentUser currentUser,
+ IHttpContextAccessor httpContextAccessor)
+ {
+ Proxy = proxy;
+ CurrentUser = currentUser;
+ HttpContextAccessor = httpContextAccessor;
+ Cache = cache;
+ }
+
+ public async Task 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"}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs
new file mode 100644
index 0000000000..71d9d8cddf
--- /dev/null
+++ b/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 GetAsync();
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs
new file mode 100644
index 0000000000..46e13bcc3d
--- /dev/null
+++ b/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 CheckAsync(string name)
+ {
+ var configuration = await ConfigurationClient.GetAsync();
+
+ return new PermissionGrantInfo(
+ name,
+ configuration.Auth.GrantedPolicies.ContainsKey(name)
+ );
+ }
+
+ public Task CheckAsync(ClaimsPrincipal claimsPrincipal, string name)
+ {
+ return CheckAsync(name);
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj
new file mode 100644
index 0000000000..8141097dc6
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.AspNetCore.Mvc.Contracts
+ Volo.Abp.AspNetCore.Mvc.Contracts
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs
new file mode 100644
index 0000000000..54a7589dd4
--- /dev/null
+++ b/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
+ {
+
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs
similarity index 86%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs
index 4981955ba0..39b3ca394b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs
+++ b/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 Policies { get; set; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
similarity index 57%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
index d7aab53482..ecafcb3274 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
+++ b/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; }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
similarity index 83%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
index 716061d507..05b5d8c7a6 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
+++ b/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> Values { get; set; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs
new file mode 100644
index 0000000000..702af56dba
--- /dev/null
+++ b/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; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs
similarity index 57%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs
index 2b820f48c6..4c521b9efc 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs
+++ b/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 GetAsync();
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs
new file mode 100644
index 0000000000..9f047c5b3c
--- /dev/null
+++ b/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 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);
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
index 332210271b..ce47163be0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
+++ b/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));
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs
index eed121566f..79372688c3 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs
+++ b/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");
}
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs
new file mode 100644
index 0000000000..53f3c3b6f9
--- /dev/null
+++ b/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
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs
new file mode 100644
index 0000000000..42635dd232
--- /dev/null
+++ b/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
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs
new file mode 100644
index 0000000000..b1958fc8af
--- /dev/null
+++ b/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
+ {
+ public AbpButtonGroupDirection Direction { get; set; } = AbpButtonGroupDirection.Horizontal;
+
+ public AbpButtonGroupSize Size { get; set; } = AbpButtonGroupSize.Default;
+
+ public AbpButtonGroupTagHelper(AbpButtonGroupTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs
new file mode 100644
index 0000000000..602e956e1e
--- /dev/null
+++ b/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
+ {
+ 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");
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs
index 65a0842d7b..dd07ff22bf 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs
+++ b/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,
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs
index 4231ac7ba6..408ba37573 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs
+++ b/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:
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs
index 1be9524800..56143ea059 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs
@@ -9,14 +9,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
public AbpButtonSize Size { get; set; } = AbpButtonSize.Default;
- public bool? Block { get; set; } = false;
-
public string BusyText { get; set; }
public string Text { get; set; }
public string Icon { get; set; }
+ public bool? Disabled { get; set; }
+
public FontIconType IconType { get; set; } = FontIconType.FontAwesome;
public AbpButtonTagHelper(AbpButtonTagHelperService service)
@@ -26,3 +26,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
}
}
}
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs
index 3d8a3bf4e8..419aff7c08 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs
@@ -13,6 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
AddClasses(context, output);
AddIcon(context, output);
AddText(context, output);
+ AddDisabled(context, output);
}
protected virtual void NormalizeTagMode(TagHelperContext context, TagHelperOutput output)
@@ -26,18 +27,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
if (TagHelper.ButtonType != AbpButtonType.Default)
{
- output.Attributes.AddClass("btn-" + TagHelper.ButtonType.ToString().ToLowerInvariant());
+ output.Attributes.AddClass("btn-" + TagHelper.ButtonType.ToString().ToLowerInvariant().Replace("_","-"));
}
if (TagHelper.Size != AbpButtonSize.Default)
{
output.Attributes.AddClass(TagHelper.Size.ToClassName());
}
-
- if (TagHelper.Block ?? false)
- {
- output.Attributes.AddClass("btn-block");
- }
}
protected virtual void AddIcon(TagHelperContext context, TagHelperOutput output)
@@ -70,5 +66,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
output.Content.AppendHtml($"{TagHelper.Text} ");
}
+
+ protected virtual void AddDisabled(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.Disabled ?? false)
+ {
+ output.Attributes.Add("disabled", "disabled");
+ }
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs
new file mode 100644
index 0000000000..7c716b88f8
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
+{
+ public class AbpButtonToolbarTagHelper : AbpTagHelper
+ {
+ public AbpButtonToolbarTagHelper(AbpButtonToolbarTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs
new file mode 100644
index 0000000000..87b378e559
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs
@@ -0,0 +1,14 @@
+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 AbpButtonToolbarTagHelperService : AbpTagHelperService
+ {
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.AddClass("btn-toolbar");
+ output.Attributes.Add("role","toolbar");
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs
index 07d7e0a50b..a6ced457e0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs
@@ -11,6 +11,14 @@
Info,
Light,
Dark,
+ Outline_Primary,
+ Outline_Secondary,
+ Outline_Success,
+ Outline_Danger,
+ Outline_Warning,
+ Outline_Info,
+ Outline_Light,
+ Outline_Dark,
Link
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs
index 8e517ea493..9a553a1be5 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs
@@ -11,12 +11,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
public AbpButtonSize Size { get; set; } = AbpButtonSize.Default;
- public bool? Block { get; set; } = false;
-
public string Text { get; set; }
public string Icon { get; set; }
+ public bool? Disabled { get; set; }
+
public FontIconType IconType { get; } = FontIconType.FontAwesome;
public AbpLinkButtonTagHelper(AbpLinkButtonTagHelperService service)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs
index dbe20def2a..ee88c4d294 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs
@@ -6,12 +6,12 @@
AbpButtonSize Size { get; }
- bool? Block { get;}
-
string Text { get; }
string Icon { get; }
+ bool? Disabled { get; }
+
FontIconType IconType { get; }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs
new file mode 100644
index 0000000000..5e95e8bf87
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ [HtmlTargetElement("abp-card", Attributes = "background")]
+ [HtmlTargetElement("abp-card-header", Attributes = "background")]
+ [HtmlTargetElement("abp-card-body", Attributes = "background")]
+ [HtmlTargetElement("abp-card-footer", Attributes = "background")]
+ public class AbpCardBackgroundTagHelper : AbpTagHelper
+ {
+ public AbpCardBackgroundType Background { get; set; } = AbpCardBackgroundType.Default;
+
+ public AbpCardBackgroundTagHelper(AbpCardBackgroundTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs
new file mode 100644
index 0000000000..248d737648
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public class AbpCardBackgroundTagHelperService : AbpTagHelperService
+ {
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ SetBackground(context, output);
+ }
+
+ protected virtual void SetBackground(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.Background == AbpCardBackgroundType.Default)
+ {
+ return;
+ }
+
+ output.Attributes.AddClass("bg-" + TagHelper.Background.ToString().ToLowerInvariant());
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs
new file mode 100644
index 0000000000..2eb9732ce8
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public enum AbpCardBackgroundType
+ {
+ Default,
+ Primary,
+ Secondary,
+ Success,
+ Danger,
+ Warning,
+ Info,
+ Light,
+ Dark,
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs
new file mode 100644
index 0000000000..0f5ccc3363
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public enum AbpCardBorderColorType
+ {
+ Default,
+ Primary,
+ Secondary,
+ Success,
+ Danger,
+ Warning,
+ Info,
+ Light,
+ Dark,
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs
new file mode 100644
index 0000000000..44b8588576
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public class AbpCardFooterTagHelper : AbpTagHelper
+ {
+ public AbpCardFooterTagHelper(AbpCardFooterTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs
new file mode 100644
index 0000000000..2a127a495b
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs
@@ -0,0 +1,14 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public class AbpCardFooterTagHelperService : AbpTagHelperService
+ {
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.AddClass("card-footer");
+ output.TagName = "div";
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs
index 6bafed3376..4a173968d0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs
@@ -3,6 +3,7 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
[HtmlTargetElement("img", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)]
+ [HtmlTargetElement("abp-image", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)]
public class AbpCardImageTagHelper : AbpTagHelper
{
[HtmlAttributeName("abp-card-image")]
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs
index 4dcf439e01..c186e8857c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs
@@ -2,6 +2,8 @@
{
public class AbpCardTagHelper : AbpTagHelper
{
+ public AbpCardBorderColorType Border { get; set; } = AbpCardBorderColorType.Default;
+
public AbpCardTagHelper(AbpCardTagHelperService tagHelperService)
: base(tagHelperService)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs
index 4eb0c286f8..29a462797d 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs
@@ -9,6 +9,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
output.TagName = "div";
output.Attributes.AddClass("card");
+
+ SetBorder(context, output);
+ }
+ protected virtual void SetBorder(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.Border == AbpCardBorderColorType.Default)
+ {
+ return;
+ }
+
+ output.Attributes.AddClass("border-" + TagHelper.Border.ToString().ToLowerInvariant());
}
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs
new file mode 100644
index 0000000000..f9787b1f18
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ [HtmlTargetElement("abp-card", Attributes = "text-color")]
+ [HtmlTargetElement("abp-card-header", Attributes = "text-color")]
+ [HtmlTargetElement("abp-card-body", Attributes = "text-color")]
+ [HtmlTargetElement("abp-card-footer", Attributes = "text-color")]
+ public class AbpCardTextColorTagHelper : AbpTagHelper
+ {
+ public AbpCardTextColorType TextColor { get; set; } = AbpCardTextColorType.Default;
+
+ public AbpCardTextColorTagHelper(AbpCardTextColorTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs
new file mode 100644
index 0000000000..36484a33f8
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public class AbpCardTextColorTagHelperService : AbpTagHelperService
+ {
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ SetTextColor(context, output);
+ }
+
+ protected virtual void SetTextColor(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.TextColor == AbpCardTextColorType.Default)
+ {
+ return;
+ }
+
+ output.Attributes.AddClass("text-" + TagHelper.TextColor.ToString().ToLowerInvariant());
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs
new file mode 100644
index 0000000000..eb415945b0
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs
@@ -0,0 +1,16 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
+{
+ public enum AbpCardTextColorType
+ {
+ Default,
+ White,
+ Primary,
+ Secondary,
+ Success,
+ Danger,
+ Warning,
+ Info,
+ Light,
+ Dark
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
index 749218cab0..ffba80fb6f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
@@ -127,7 +127,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
{
if (string.IsNullOrWhiteSpace(TagHelper.Id))
{
- TagHelper.Id = Guid.NewGuid().ToString("N");
+ TagHelper.Id = "C" + Guid.NewGuid().ToString("N");
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
index fabdb36452..1f9f57c567 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
@@ -59,7 +59,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
if (string.IsNullOrWhiteSpace(TagHelper.Id))
{
- TagHelper.Id = Guid.NewGuid().ToString("N");
+ TagHelper.Id = "A" + Guid.NewGuid().ToString("N");
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
index 1d0a9234fd..20e62604a9 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
@@ -55,7 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
if (string.IsNullOrWhiteSpace(TagHelper.Id))
{
- TagHelper.Id = Guid.NewGuid().ToString("N");
+ TagHelper.Id = "A" + Guid.NewGuid().ToString("N");
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs
index 0d4aecab31..a50907addb 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs
@@ -4,6 +4,8 @@
{
public string Id { get; set; }
+ public bool? Multi { get; set; }
+
public bool? Show { get; set; }
public AbpCollapseBodyTagHelper(AbpCollapseBodyTagHelperService tagHelperService)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
index 56b04df63d..10e49b92a7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
@@ -17,16 +17,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
output.Attributes.AddClass("show");
}
- var innerContent = (await output.GetChildContentAsync()).GetContent();
-
- var body = GetBody(context, output, innerContent);
+ if (TagHelper.Multi ?? false)
+ {
+ output.Attributes.AddClass("multi-collapse");
+ }
- output.Content.SetHtmlContent(body);
- }
+ var innerContent = (await output.GetChildContentAsync()).GetContent();
- protected virtual string GetBody(TagHelperContext context, TagHelperOutput output, string innerContent)
- {
- return "" + innerContent + "
";
+ output.Content.SetHtmlContent(innerContent);
}
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs
index 2e6da81cf0..6b8fc8c30b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs
@@ -1,11 +1,14 @@
-using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
+
+ [HtmlTargetElement("abp-button", Attributes = "abp-collapse-id")]
+ [HtmlTargetElement("a", Attributes = "abp-collapse-id")]
public class AbpCollapseButtonTagHelper : AbpTagHelper
{
- public AbpButtonType ButonType { get; set; } = AbpButtonType.Default;
-
+ [HtmlAttributeName("abp-collapse-id")]
public string BodyId { get; set; }
public AbpCollapseButtonTagHelper(AbpCollapseButtonTagHelperService tagHelperService)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs
index c2221035c1..6b7d74b866 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs
@@ -8,20 +8,48 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
- output.TagName = "button";
- output.Attributes.AddClass("btn");
- output.Attributes.Add("data-toggle","collapse");
- output.Attributes.Add("aria-expanded","false");
- output.Attributes.Add("type","button");
- output.Attributes.Add("data-target", "#" +TagHelper.BodyId);
+
+
+ AddCommonAttributes(context, output);
+
+ if (output.TagName == "abp-button" || output.TagName == "button")
+ {
+ AddButtonAttributes(context,output);
+ }
+ else if (output.TagName == "a")
+ {
+ AddLinkAttributes(context, output);
+ }
+ }
+
+ protected virtual void AddCommonAttributes(TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.Add("data-toggle", "collapse");
+ output.Attributes.Add("aria-expanded", "false");
output.Attributes.Add("aria-controls", TagHelper.BodyId);
+ }
+ protected virtual void AddButtonAttributes(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.BodyId.Trim().Split(' ').Length > 1)
+ {
+ output.Attributes.Add("data-target", ".multi-collapse");
+ return;
+ }
- if (TagHelper.ButonType != AbpButtonType.Default)
+ output.Attributes.Add("data-target", "#" + TagHelper.BodyId);
+ }
+
+ protected virtual void AddLinkAttributes(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TagHelper.BodyId.Trim().Split(' ').Length > 1)
{
- output.Attributes.AddClass("btn-" + TagHelper.ButonType.ToString().ToLowerInvariant());
+ output.Attributes.Add("href", ".multi-collapse");
+ return;
}
+
+ output.Attributes.Add("href", "#" + TagHelper.BodyId);
}
-
+
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
index 60a34a71f1..8b01781602 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
@@ -125,6 +125,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
buttonTag.TagName = "a";
buttonTag.Attributes.RemoveAll("type");
buttonTag.Attributes.Add("roles", "button");
+ buttonTag.Attributes.Add("href", "#");
if (TagHelper.NavLink??false)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs
new file mode 100644
index 0000000000..4c5e82fac7
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
+{
+ public class AbpDropdownItemTextTagHelper : AbpTagHelper
+ {
+ public AbpDropdownItemTextTagHelper(AbpDropdownItemTextTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs
new file mode 100644
index 0000000000..8cd84eade6
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs
@@ -0,0 +1,14 @@
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
+{
+ public class AbpDropdownItemTextTagHelperService : AbpTagHelperService
+ {
+ public override void Process(TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.AddClass("dropdown-item-text");
+ output.TagName = "span";
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs
index a6c5c80c06..141d995fd7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs
@@ -18,6 +18,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public bool? SubmitButton { get; set; }
+ public bool? RequiredSymbols { get; set; } = true;
+
#region MvcFormTagHelperAttiributes
private const string ActionAttributeName = "asp-action";
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
index 3d7504f72d..fa3ec9cce6 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
@@ -192,6 +192,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var abpInputTagHelper = _serviceProvider.GetRequiredService();
abpInputTagHelper.AspFor = model;
abpInputTagHelper.ViewContext = TagHelper.ViewContext;
+ abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true;
RenderTagHelper(new TagHelperAttributeList(), context, abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs
new file mode 100644
index 0000000000..79070b559e
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs
@@ -0,0 +1,10 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
+{
+ public enum AbpFormControlSize
+ {
+ Default,
+ Small,
+ Medium,
+ Large
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
index de93ff4b1d..0c5ac5dd22 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
@@ -10,14 +10,22 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public string Label { get; set; }
+ [HtmlAttributeName("info")]
+ public string InfoText { get; set; }
+
[HtmlAttributeName("disabled")]
public bool IsDisabled { get; set; } = false;
[HtmlAttributeName("readonly")]
- public bool IsReadonly { get; set; } = false;
+ public bool? IsReadonly { get; set; } = false;
public bool AutoFocus { get; set; }
+ public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default;
+
+ [HtmlAttributeNotBound]
+ public bool DisplayRequiredSymbol { get; set; } = true;
+
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
index b5abe780ae..bc48d7b1d8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers;
@@ -12,11 +13,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder;
+ private readonly IAbpTagHelperLocalizer _tagHelperLocalizer;
- public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder)
+ public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer)
{
_generator = generator;
_encoder = encoder;
+ _tagHelperLocalizer = tagHelperLocalizer;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
@@ -43,6 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.TagName = "div";
LeaveOnlyGroupAttributes(context, output);
output.Attributes.AddClass(isCheckbox ? "form-check" : "form-group");
+ output.Attributes.AddClass(isCheckbox ? "mb-2" : "");
output.Content.SetHtmlContent(output.Content.GetContent() + innerHtml);
}
}
@@ -50,17 +54,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox)
{
var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox);
+
var inputHtml = RenderTagHelperOutput(inputTag, _encoder);
var label = GetLabelAsHtml(context, output, inputTag, isCheckbox);
-
+ var info = GetInfoAsHtml(context, output, inputTag, isCheckbox);
var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag);
- return GetContent(context, output, label, inputHtml, validation, isCheckbox);
+ return GetContent(context, output, label, inputHtml, validation, info, isCheckbox);
}
protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
{
- if (inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden"))
+ if (IsOutputHidden(inputTag))
{
return "";
}
@@ -76,14 +81,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
}
- protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, bool isCheckbox)
+ protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox)
{
var innerContent = isCheckbox ?
- inputHtml + Environment.NewLine + label :
- label + Environment.NewLine + inputHtml;
+ inputHtml + label :
+ label + inputHtml;
- return Environment.NewLine + innerContent + Environment.NewLine +
- Environment.NewLine + validation + Environment.NewLine;
+ return innerContent + infoHtml + validation;
}
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox)
@@ -121,14 +125,28 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ConvertToTextAreaIfTextArea(inputTagHelperOutput);
AddDisabledAttribute(inputTagHelperOutput);
- AddReadOnlyAttribute(inputTagHelperOutput);
AddAutoFocusAttribute(inputTagHelperOutput);
isCheckbox = IsInputCheckbox(context, output, inputTagHelperOutput.Attributes);
- inputTagHelperOutput.Attributes.AddClass(isCheckbox ? "form-check-input" : "form-control");
+ AddFormControlClass(context, output, isCheckbox, inputTagHelperOutput);
+ AddReadOnlyAttribute(inputTagHelperOutput);
+ AddPlaceholderAttribute(inputTagHelperOutput);
+ AddInfoTextId(inputTagHelperOutput);
return inputTagHelperOutput;
}
+ private void AddFormControlClass(TagHelperContext context, TagHelperOutput output, bool isCheckbox, TagHelperOutput inputTagHelperOutput)
+ {
+ var className = "form-control";
+
+ if (isCheckbox)
+ {
+ className = "form-check-input";
+ }
+
+ inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output));
+ }
+
protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput)
{
if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus"))
@@ -139,26 +157,56 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{
- if (inputTagHelperOutput.Attributes.ContainsName("disabled"))
+ if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false &&
+ (TagHelper.IsDisabled || GetAttribute(TagHelper.AspFor.ModelExplorer) != null))
+ {
+ inputTagHelperOutput.Attributes.Add("disabled", "");
+ }
+ }
+
+ protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput)
+ {
+ if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false &&
+ (TagHelper.IsReadonly != false || GetAttribute(TagHelper.AspFor.ModelExplorer) != null))
+ {
+ inputTagHelperOutput.Attributes.Add("readonly", "");
+ }
+ }
+
+ protected virtual void AddPlaceholderAttribute(TagHelperOutput inputTagHelperOutput)
+ {
+ if (inputTagHelperOutput.Attributes.ContainsName("placeholder"))
{
return;
}
- else if (TagHelper.IsDisabled || GetAttribute(TagHelper.AspFor.ModelExplorer) != null)
+
+ var attribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+
+ if (attribute != null)
{
- inputTagHelperOutput.Attributes.Add("disabled", "");
+ var placeholderLocalized = _tagHelperLocalizer.GetLocalizedText(attribute.Value, TagHelper.AspFor.ModelExplorer);
+
+ inputTagHelperOutput.Attributes.Add("placeholder", placeholderLocalized);
}
}
- protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput)
+ protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{
- if (inputTagHelperOutput.Attributes.ContainsName("readonly"))
+ if (GetAttribute(TagHelper.AspFor.ModelExplorer) == null)
{
return;
}
- else if (TagHelper.IsReadonly || GetAttribute(TagHelper.AspFor.ModelExplorer) != null)
+
+ var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id");
+
+ if (idAttr == null)
{
- inputTagHelperOutput.Attributes.Add("readonly", "");
+ return;
}
+
+ var infoText = _tagHelperLocalizer.GetLocalizedText(idAttr.Value + "InfoText", TagHelper.AspFor.ModelExplorer);
+
+ inputTagHelperOutput.Attributes.Add("aria-describedby", infoText);
}
protected virtual bool IsInputCheckbox(TagHelperContext context, TagHelperOutput output, TagHelperAttributeList attributes)
@@ -168,21 +216,70 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetLabelAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
{
- if (inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden"))
+ if (IsOutputHidden(inputTag))
{
return "";
}
if (string.IsNullOrEmpty(TagHelper.Label))
{
- return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox);
+ return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag);
}
var checkboxClass = isCheckbox ? "class=\"form-check-label\" " : "";
return ""
+ TagHelper.Label +
- " ";
+ "" + GetRequiredSymbol(context, output, inputTag);
+ }
+
+ protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
+ {
+ if (!TagHelper.DisplayRequiredSymbol)
+ {
+ return "";
+ }
+
+ return GetAttribute(TagHelper.AspFor.ModelExplorer) != null ? " * ":"";
+ }
+
+ protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
+ {
+ if (IsOutputHidden(inputTag))
+ {
+ return "";
+ }
+
+ if (isCheckbox)
+ {
+ return "";
+ }
+
+ var text = "";
+
+ if (!string.IsNullOrEmpty(TagHelper.InfoText))
+ {
+ text = TagHelper.InfoText;
+ }
+ else
+ {
+ var infoAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+ if (infoAttribute != null)
+ {
+ text = infoAttribute.Text;
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
+ var localizedText = _tagHelperLocalizer.GetLocalizedText(text, TagHelper.AspFor.ModelExplorer);
+
+ return "" +
+ localizedText +
+ " ";
}
protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output, bool isCheckbox)
@@ -254,5 +351,32 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.Add(newAttritube);
}
}
+
+ protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
+ {
+ var attribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+
+ if (attribute != null)
+ {
+ TagHelper.Size = attribute.Size;
+ }
+
+ switch (TagHelper.Size)
+ {
+ case AbpFormControlSize.Small:
+ return "form-control-sm";
+ case AbpFormControlSize.Medium:
+ return "form-control-md";
+ case AbpFormControlSize.Large:
+ return "form-control-lg";
+ }
+
+ return "";
+ }
+
+ protected virtual bool IsOutputHidden(TagHelperOutput inputTag)
+ {
+ return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden");
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs
index d3635a4753..c299826a07 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
index 13b3d29cf7..2968085781 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
@@ -6,20 +6,28 @@ using System.Text;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
+using Microsoft.Extensions.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
public class AbpRadioInputTagHelperService : AbpTagHelperService
{
+ private readonly IAbpTagHelperLocalizer _tagHelperLocalizer;
+
+ public AbpRadioInputTagHelperService(IAbpTagHelperLocalizer tagHelperLocalizer)
+ {
+ _tagHelperLocalizer = tagHelperLocalizer;
+ }
+
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var selectItems = GetSelectItems(context,output);
+ SetSelectedValue(context, output, selectItems);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer);
var html = GetHtml(context, output, selectItems);
-
AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, html, order, out var surpress);
if (surpress)
@@ -60,33 +68,59 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual List GetSelectItems(TagHelperContext context, TagHelperOutput output)
{
- var selectItems = TagHelper.AspItems?.ToList();
+ if (TagHelper.AspItems != null)
+ {
+ return TagHelper.AspItems.ToList();
+ }
- if (TagHelper.AspItems == null &&
- !GetSelectItemsIfProvidedByEnum(context, output, TagHelper.AspFor.ModelExplorer, out selectItems) &&
- !GetSelectItemsIfProvidedFromAttribute(context, output, TagHelper.AspFor.ModelExplorer, out selectItems))
+ if (TagHelper.AspFor.ModelExplorer.Metadata.IsEnum)
{
- throw new Exception("No items provided for select attribute.");
+ return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
}
- SetSelectedValue(context, output, selectItems);
+ var selectItemsAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+ if (selectItemsAttribute != null)
+ {
+ return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
+ }
+
+ throw new Exception("No items provided for select attribute.");
+ }
+
+ protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer)
+ {
+ var localizer = _tagHelperLocalizer.GetLocalizer(explorer);
+
+ var selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
+ .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null;
return selectItems;
}
- protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems)
+ protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName)
{
- selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
- .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = t.Name }).ToList() : null;
+ if (localizer == null)
+ {
+ return propertyName;
+ }
+
+ var localizedString = localizer[enumType.Name + "." + propertyName];
- return selectItems != null;
+ return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value;
}
- protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems)
+ protected virtual List GetSelectItemsFromAttribute(
+ SelectItems selectItemsAttribute,
+ ModelExplorer explorer)
{
- selectItems = GetAttribute(explorer)?.GetItems(explorer)?.ToList();
+ var selectItems = selectItemsAttribute.GetItems(explorer)?.ToList();
+
+ if (selectItems == null)
+ {
+ return new List();
+ }
- return selectItems != null;
+ return selectItems;
}
protected virtual void SetSelectedValue(TagHelperContext context, TagHelperOutput output, List selectItems)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs
new file mode 100644
index 0000000000..415abf2ef7
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs
@@ -0,0 +1,9 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
+{
+ public enum AbpReadonlyInputType
+ {
+ False,
+ True,
+ True_PlainText
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs
index 889fe4208d..f8cdd35a7e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs
@@ -13,6 +13,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public IEnumerable AspItems { get; set; }
+ public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default;
+
+ [HtmlAttributeName("info")]
+ public string InfoText { get; set; }
+
+ [HtmlAttributeNotBound]
+ public bool DisplayRequiredSymbol { get; set; } = true;
+
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
index 8607348fff..2df060e2e5 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
@@ -7,6 +8,7 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
+using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
@@ -15,11 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder;
+ private readonly IAbpTagHelperLocalizer _tagHelperLocalizer;
- public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder)
+ public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer)
{
_generator = generator;
_encoder = encoder;
+ _tagHelperLocalizer = tagHelperLocalizer;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
@@ -37,6 +41,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
else
{
output.TagName = "div";
+ LeaveOnlyGroupAttributes(context, output);
output.Attributes.AddClass("form-group");
output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetHtmlContent(innerHtml);
@@ -48,8 +53,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var selectTag = GetSelectTag(context, output);
var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder);
var label = GetLabelAsHtml(context, output, selectTag);
+ var validation = GetValidationAsHtml(context, output, selectTag);
+ var infoText = GetInfoAsHtml(context, output, selectTag);
- return label + Environment.NewLine + selectAsHtml;
+ return label + Environment.NewLine + selectAsHtml + Environment.NewLine + infoText + Environment.NewLine + validation;
}
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml)
@@ -59,21 +66,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual TagHelperOutput GetSelectTag(TagHelperContext context, TagHelperOutput output)
{
- var selectItems = GetSelectItems(context, output);
-
var selectTagHelper = new SelectTagHelper(_generator)
{
For = TagHelper.AspFor,
- Items = selectItems,
+ Items = GetSelectItems(context, output),
ViewContext = TagHelper.ViewContext
};
- var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), context, selectTagHelper, "select", TagMode.StartTagAndEndTag);
+ var selectTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, selectTagHelper, "select", TagMode.StartTagAndEndTag);
- inputTagHelperOutput.Attributes.Add("class", "form-control");
- AddDisabledAttribute(inputTagHelperOutput);
+ selectTagHelperOutput.Attributes.AddClass("form-control");
+ selectTagHelperOutput.Attributes.AddClass(GetSize(context, output));
+ AddDisabledAttribute(selectTagHelperOutput);
+ AddInfoTextId(selectTagHelperOutput);
- return inputTagHelperOutput;
+ return selectTagHelperOutput;
}
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
@@ -88,76 +95,128 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual List GetSelectItems(TagHelperContext context, TagHelperOutput output)
{
- var selectItems = TagHelper.AspItems?.ToList();
+ if (TagHelper.AspItems != null)
+ {
+ return TagHelper.AspItems.ToList();
+ }
- if (TagHelper.AspItems == null &&
- !GetSelectItemsIfProvidedByEnum(context, output, TagHelper.AspFor.ModelExplorer, out selectItems) &&
- !GetSelectItemsIfProvidedFromAttribute(context, output, TagHelper.AspFor.ModelExplorer, out selectItems))
+ if (TagHelper.AspFor.ModelExplorer.Metadata.IsEnum)
{
- throw new Exception("No items provided for select attribute.");
+ return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
}
- SetSelectedValue(context, output, selectItems);
+ var selectItemsAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+ if (selectItemsAttribute != null)
+ {
+ return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
+ }
- return selectItems;
+ throw new Exception("No items provided for select attribute.");
}
protected virtual string GetLabelAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag)
{
if (!string.IsNullOrEmpty(TagHelper.Label))
{
- return "" + TagHelper.Label + " ";
+ return "" + TagHelper.Label + " " + GetRequiredSymbol(context, output);
}
- return GetLabelAsHtmlUsingTagHelper(context, output);
+ return GetLabelAsHtmlUsingTagHelper(context, output) + GetRequiredSymbol(context, output);
}
- protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems)
+
+ protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output)
{
- selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
- .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = t.Name }).ToList() : null;
+ if (!TagHelper.DisplayRequiredSymbol)
+ {
+ return "";
+ }
- return selectItems != null;
+ return GetAttribute(TagHelper.AspFor.ModelExplorer) != null ? " * " : "";
}
- protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems)
+ protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{
- selectItems = GetAttribute(explorer)?.GetItems(explorer)?.ToList();
+ if (GetAttribute(TagHelper.AspFor.ModelExplorer) == null)
+ {
+ return;
+ }
- return selectItems != null;
- }
+ var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id");
- protected virtual void SetSelectedValue(TagHelperContext context, TagHelperOutput output, List selectItems)
- {
- if (!selectItems.Any(si => si.Selected))
+ if (idAttr == null)
{
- var selectedValue = GetSelectedValue(context, output);
+ return;
+ }
- var itemToBeSelected = selectItems.FirstOrDefault(si => si.Value.ToString() == selectedValue);
+ var infoText = _tagHelperLocalizer.GetLocalizedText(idAttr.Value + "InfoText", TagHelper.AspFor.ModelExplorer);
- if (itemToBeSelected != null)
+ inputTagHelperOutput.Attributes.Add("aria-describedby", infoText);
+ }
+
+ protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
+ {
+ var text = "";
+
+ if (!string.IsNullOrEmpty(TagHelper.InfoText))
+ {
+ text = TagHelper.InfoText;
+ }
+ else
+ {
+ var infoAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+ if (infoAttribute != null)
+ {
+ text = infoAttribute.Text;
+ }
+ else
{
- itemToBeSelected.Selected = true;
+ return "";
}
}
+
+ var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
+ var localizedText = _tagHelperLocalizer.GetLocalizedText(text, TagHelper.AspFor.ModelExplorer);
+
+ return "" +
+ localizedText +
+ " ";
}
- protected virtual string GetSelectedValue(TagHelperContext context, TagHelperOutput output)
+ protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer)
{
- var modelExplorer = TagHelper.AspFor.ModelExplorer;
+ var localizer = _tagHelperLocalizer.GetLocalizer(explorer);
- if (modelExplorer.Metadata.IsEnum)
- {
- var baseType = modelExplorer.Model?.GetType().GetEnumUnderlyingType();
+ var selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
+ .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null;
- if (baseType == null) { return null; }
+ return selectItems;
+ }
- return Convert.ChangeType(modelExplorer.Model, baseType)?.ToString() ?? "";
+ protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName)
+ {
+ if (localizer == null)
+ {
+ return propertyName;
}
- else
+
+ var localizedString = localizer[enumType.Name + "." + propertyName];
+
+ return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value;
+ }
+
+ protected virtual List GetSelectItemsFromAttribute(
+ SelectItems selectItemsAttribute,
+ ModelExplorer explorer)
+ {
+ var selectItems = selectItemsAttribute.GetItems(explorer)?.ToList();
+
+ if (selectItems == null)
{
- return modelExplorer.Model?.ToString();
+ return new List();
}
+
+ return selectItems;
}
protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output)
@@ -170,5 +229,70 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true);
}
+
+ protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
+ {
+ var validationMessageTagHelper = new ValidationMessageTagHelper(_generator)
+ {
+ For = TagHelper.AspFor,
+ ViewContext = TagHelper.ViewContext
+ };
+
+ var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
+
+ return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
+ }
+
+ protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
+ {
+ var attribute = GetAttribute(TagHelper.AspFor.ModelExplorer);
+
+ if (attribute != null)
+ {
+ TagHelper.Size = attribute.Size;
+ }
+
+ switch (TagHelper.Size)
+ {
+ case AbpFormControlSize.Small:
+ return "form-control-sm";
+ case AbpFormControlSize.Medium:
+ return "form-control-md";
+ case AbpFormControlSize.Large:
+ return "form-control-lg";
+ }
+
+ return "";
+ }
+
+ protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output)
+ {
+ var groupPrefix = "group-";
+
+ var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList();
+ var attrList = new TagHelperAttributeList();
+
+ foreach (var tagHelperAttribute in tagHelperAttributes)
+ {
+ attrList.Add(tagHelperAttribute);
+ }
+
+ return attrList;
+ }
+
+ protected virtual void LeaveOnlyGroupAttributes(TagHelperContext context, TagHelperOutput output)
+ {
+ var groupPrefix = "group-";
+ var tagHelperAttributes = output.Attributes.Where(a => a.Name.StartsWith(groupPrefix)).ToList();
+
+ output.Attributes.Clear();
+
+ foreach (var tagHelperAttribute in tagHelperAttributes)
+ {
+ var nameWithoutPrefix = tagHelperAttribute.Name.Substring(groupPrefix.Length);
+ var newAttritube = new TagHelperAttribute(nameWithoutPrefix, tagHelperAttribute.Value);
+ output.Attributes.Add(newAttritube);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs
index f43754cc22..6ef18e1d57 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs
new file mode 100644
index 0000000000..f85775f156
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
+{
+ [AttributeUsage(AttributeTargets.Property)]
+ public class FormControlSize : Attribute
+ {
+ public AbpFormControlSize Size { get; set; }
+
+ public FormControlSize(AbpFormControlSize size)
+ {
+ Size = size;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs
new file mode 100644
index 0000000000..004ab7dc64
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
+{
+ [AttributeUsage(AttributeTargets.Property)]
+ public class InputInfoText : Attribute
+ {
+ public string Text { get; set; }
+
+ public InputInfoText(string text)
+ {
+ Text = text;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs
new file mode 100644
index 0000000000..829301021b
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
+{
+ [AttributeUsage(AttributeTargets.Property)]
+ public class Placeholder : Attribute
+ {
+ public string Value { get; set; }
+
+ public Placeholder(string value)
+ {
+ Value = value;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs
index 6cef8594b3..f22c3d53da 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs
@@ -1,15 +1,19 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
[AttributeUsage(AttributeTargets.Property)]
public class ReadOnlyInput : Attribute
{
+ public bool PlainText { get; set; }
+
public ReadOnlyInput()
{
}
+
+ public ReadOnlyInput(bool plainText)
+ {
+ PlainText = plainText;
+ }
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs
index fc8ce1016a..7c5a0c0724 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs
deleted file mode 100644
index fdd6b973a4..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
-{
- public class AbpColBreakTagHelper : AbpTagHelper
- {
- public AbpColBreakTagHelper(AbpColBreakTagHelperService tagHelperService)
- : base(tagHelperService)
- {
-
- }
- }
-}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs
new file mode 100644
index 0000000000..492a16ff21
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
+{
+ public class AbpColumnBreakerTagHelper : AbpTagHelper
+ {
+ public AbpColumnBreakerTagHelper(AbpColumnBreakerTagHelperService tagHelperService)
+ : base(tagHelperService)
+ {
+
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs
similarity index 82%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs
index b483f275b2..f6190f2332 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs
@@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{
- public class AbpColBreakTagHelperService : AbpTagHelperService
+ public class AbpColumnBreakerTagHelperService : AbpTagHelperService
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
index 900b72fe25..ead3367ac7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
@@ -6,6 +6,8 @@
public HorizontalAlign HAlign { get; set; } = HorizontalAlign.Default;
+ public bool? Gutters { get; set; } = true;
+
public AbpRowTagHelper(AbpRowTagHelperService tagHelperService)
: base(tagHelperService)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
index 12609600d7..ecbe5db97e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
@@ -12,6 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
ProcessVerticalAlign(output);
ProcessHorizontalAlign(output);
+ ProcessGutters(output);
}
protected virtual void ProcessVerticalAlign(TagHelperOutput output)
@@ -33,5 +34,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass("justify-content-" + TagHelper.HAlign.ToString().ToLowerInvariant());
}
+
+ protected virtual void ProcessGutters(TagHelperOutput output)
+ {
+ if (TagHelper.Gutters ?? true)
+ {
+ return;
+ }
+
+ output.Attributes.AddClass("no-gutters");
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs
new file mode 100644
index 0000000000..8351e47082
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Reflection;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.Extensions.Localization;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
+{
+ public interface IAbpTagHelperLocalizer : ITransientDependency
+ {
+ string GetLocalizedText(string text, ModelExplorer explorer);
+
+ IStringLocalizer GetLocalizer(ModelExplorer explorer);
+
+ IStringLocalizer GetLocalizer(Assembly assembly);
+
+ IStringLocalizer GetLocalizer(Type resourceType);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs
deleted file mode 100644
index 4a2f1cb622..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
-{
- public enum AbpImagePosition
- {
- Default,
- Right,
- Left,
- Center
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs
deleted file mode 100644
index afc36f660c..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
-{
- public class AbpImageTagHelper : AbpTagHelper
- {
- public bool? Responsive { get; set; }
-
- public bool? Thumbnail { get; set; }
-
- public bool? Rounded { get; set; }
-
- public AbpImagePosition Position { get; set; } = AbpImagePosition.Default;
-
- public string Alt { get; set; }
-
- public string Src { get; set; }
-
- public AbpImageTagHelper(AbpImageTagHelperService tagHelperService)
- : base(tagHelperService)
- {
-
- }
- }
-}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs
deleted file mode 100644
index c03eee480e..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using Microsoft.AspNetCore.Razor.TagHelpers;
-using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
-
-namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
-{
- public class AbpImageTagHelperService : AbpTagHelperService
- {
- public override void Process(TagHelperContext context, TagHelperOutput output)
- {
- output.TagName = "img";
- SetSourceFile(context,output);
- SetPosition(context,output);
- SetResponsive(context,output);
- SetThumbnail(context,output);
- SetRounded(context,output);
- SetAlt(context,output);
- }
-
- protected virtual void SetSourceFile(TagHelperContext context, TagHelperOutput output) {
- output.Attributes.Add("src",TagHelper.Src);
- }
-
- protected virtual void SetPosition(TagHelperContext context, TagHelperOutput output)
- {
- if (TagHelper.Position == default)
- {
- return;
- }
- if (TagHelper.Position == AbpImagePosition.Left || TagHelper.Position == AbpImagePosition.Right)
- {
- output.Attributes.AddClass("float-" + TagHelper.Position.ToString().ToLowerInvariant());
- }
- if (TagHelper.Position == AbpImagePosition.Center)
- {
- output.PreElement.SetHtmlContent("");
- output.PostElement.SetHtmlContent("
");
- }
- }
-
- protected virtual void SetResponsive(TagHelperContext context, TagHelperOutput output) {
- if (TagHelper.Responsive ?? false)
- {
- output.Attributes.AddClass("img-fluid");
- }
- }
-
- protected virtual void SetThumbnail(TagHelperContext context, TagHelperOutput output)
- {
- if (TagHelper.Thumbnail ?? false)
- {
- output.Attributes.AddClass("img-thumbnail");
- }
- }
-
- protected virtual void SetRounded(TagHelperContext context, TagHelperOutput output)
- {
- if (TagHelper.Rounded ?? false)
- {
- output.Attributes.AddClass("rounded");
- }
- }
-
- protected virtual void SetAlt(TagHelperContext context, TagHelperOutput output)
- {
- output.Attributes.Add("alt",TagHelper.Alt);
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs
index 5524f221ff..aa61832ab9 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs
@@ -4,6 +4,8 @@
{
public AbpModalSize Size { get; set; } = AbpModalSize.Default;
+ public bool? Centered { get; set; } = false;
+
public AbpModalTagHelper(AbpModalTagHelperService tagHelperService)
: base(tagHelperService)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs
index 23453df1d0..8106db4661 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs
@@ -36,6 +36,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{
var classNames = new StringBuilder("modal-dialog");
+ if (TagHelper.Centered ?? false)
+ {
+ classNames.Append(" ");
+ classNames.Append("modal-dialog-centered");
+ }
+
if (TagHelper.Size != AbpModalSize.Default)
{
classNames.Append(" ");
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs
index e7655c6073..40f25951fe 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs
@@ -2,8 +2,6 @@
{
public class AbpNavItemTagHelper : AbpTagHelper
{
- public bool? Active { get; set; }
-
public bool? Dropdown { get; set; }
public AbpNavItemTagHelper(AbpNavItemTagHelperService tagHelperService)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs
index b4e8575ac8..ced733272c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs
@@ -11,7 +11,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.Attributes.AddClass("nav-item");
SetDropdownClass(context, output);
- SetActiveClass(context, output);
}
protected virtual void SetDropdownClass(TagHelperContext context, TagHelperOutput output)
@@ -21,13 +20,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.Attributes.AddClass("dropdown");
}
}
-
- protected virtual void SetActiveClass(TagHelperContext context, TagHelperOutput output)
- {
- if (TagHelper.Active ?? false)
- {
- output.Attributes.AddClass("active");
- }
- }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs
index 7809adc98b..1a534b5efb 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs
@@ -8,8 +8,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
public bool? Active { get; set; }
public bool? Disabled { get; set; }
-
- public string Href { get; set; }
public AbpNavLinkTagHelper(AbpNavLinkTagHelperService tagHelperService)
: base(tagHelperService)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs
index 48f4867662..75f4285530 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs
@@ -13,11 +13,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.TagName = "a";
output.TagMode = TagMode.StartTagAndEndTag;
SetClasses(context, output);
-
- if (!string.IsNullOrWhiteSpace(TagHelper.Href))
- {
- output.Attributes.Add("href", TagHelper.Href);
- }
}
protected virtual void SetClasses(TagHelperContext context, TagHelperOutput output)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs
index 400769a992..1b53894ac2 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs
@@ -28,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
{
if (string.IsNullOrWhiteSpace(TagHelper.Id))
{
- TagHelper.Id = Guid.NewGuid().ToString("N");
+ TagHelper.Id = "N" + Guid.NewGuid().ToString("N");
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
index 6fda6ccd63..e3293cddca 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
@@ -13,13 +13,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
{
private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder;
- private readonly IStringLocalizer _localizer;
+ private readonly IAbpTagHelperLocalizer _tagHelperLocalizer;
- public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IStringLocalizer localizer)
+ public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer)
{
_generator = generator;
_encoder = encoder;
- _localizer = localizer;
+ _tagHelperLocalizer = tagHelperLocalizer;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
@@ -117,11 +117,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
protected virtual string RenderAnchorTagHelperLinkHtml(TagHelperContext context, TagHelperOutput output, string currentPage, string localizationKey)
{
+ var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource));
+
var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList);
var tagHelperOutput = GetInnerTagHelper(attributeList, context, anchorTagHelper, "a", TagMode.StartTagAndEndTag);
- tagHelperOutput.Content.SetHtmlContent(_localizer[localizationKey]);
+ tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]);
var renderedHtml = RenderTagHelperOutput(tagHelperOutput, _encoder);
@@ -150,15 +152,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
protected virtual string GetOpeningTags(TagHelperContext context, TagHelperOutput output)
{
+ var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource));
+
var pagerInfo = (TagHelper.ShowInfo ?? false) ?
- " " + _localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "
\r\n"
+ " " + localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "
\r\n"
: "";
return
pagerInfo +
" \r\n" +
" \r\n" +
- "