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 d0f5369ff2..c8c021e728 100644
--- a/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
+++ b/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
@@ -1,10 +1,8 @@
-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;
@@ -26,7 +24,6 @@ using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
using Volo.Abp.UI;
-using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using Volo.AbpWebSite.Bundling;
using Volo.Blogging;
@@ -49,14 +46,6 @@ namespace Volo.AbpWebSite
)]
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();
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..5c410ca673 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 @@
-
+
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..57a1da9e7b 100644
--- a/build-all.ps1
+++ b/build-all.ps1
@@ -31,6 +31,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.props b/common.props
index ab2b655172..1361ab14b9 100644
--- a/common.props
+++ b/common.props
@@ -1,7 +1,7 @@
latest
- 0.10.0
+ 0.12.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/Dynamic-CSharp-API-Clients.md b/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
index eee2abacc0..0b0667dd0d 100644
--- a/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
+++ b/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
@@ -7,13 +7,13 @@ ABP can dynamically create C# API client proxies to call remote HTTP services (R
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 IBookService : IApplicationService
+public interface IBookAppService : IApplicationService
{
Task> GetListAsync();
}
````
-Your interface should implement the `IRemoteService` interface. Since the `IApplicationService` inherits the `IRemoteService` interface, the `IBookService` above satisfies this condition.
+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.
@@ -45,13 +45,6 @@ public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
- //Configure remote end point
- context.Services.Configure(options =>
- {
- options.RemoteServices.Default =
- new RemoteServiceConfiguration("http://localhost:53929/");
- });
-
//Create dynamic client proxies
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly
@@ -60,10 +53,24 @@ public class MyClientAppModule : AbpModule
}
````
-`RemoteServiceOptions` is used to configure endpoints for remote services (This example sets the default endpoint while you can have different service endpoints used by different clients. See the "Multiple Remote Service Endpoint" section).
-
`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:
@@ -71,9 +78,9 @@ It's straightforward to use. Just inject the service interface in the client app
````csharp
public class MyService : ITransientDependency
{
- private readonly IBookService _bookService;
+ private readonly IBookAppService _bookService;
- public MyService(IBookService bookService)
+ public MyService(IBookAppService bookService)
{
_bookService = bookService;
}
@@ -89,40 +96,34 @@ public class MyService : ITransientDependency
}
````
-This sample injects the `IBookService` service interface defined above. The dynamic client proxy implementation makes an HTTP call whenever a service method is called by the client.
+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.
-## Configuration Details
+### IHttpClientProxy Interface
-### RemoteServiceOptions
+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.
-While you can configure `RemoteServiceOptions` as the example shown above, you can let it to read from your `appsettings.json` file. Add a `RemoteServices` section to your `appsettings.json` file:
+## Configuration
-````json
-{
- "RemoteServices": {
- "Default": {
- "BaseUrl": "http://localhost:53929/"
- }
- }
-}
-````
+### RemoteServiceOptions
-Then you can pass your `IConfigurationRoot` instance directly to the `Configure()` method as shown below:
+`RemoteServiceOptions` is automatically set from the `appsettings.json` by default. Alternatively, you can use `Configure` method to set or override it. Example:
````csharp
-var configuration = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
- .AddJsonFile("appsettings.json")
- .Build();
-
-context.Services.Configure(configuration);
+public override void ConfigureServices(ServiceConfigurationContext context)
+{
+ context.Services.Configure(options =>
+ {
+ options.RemoteServices.Default =
+ new RemoteServiceConfiguration("http://localhost:53929/");
+ });
+
+ //...
+}
````
-This approach is useful since it's easy to change the configuration later without touching to the code.
+### Multiple Remote Service Endpoints
-#### Multiple Remote Service Endpoint
-
-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 endpoint). In this case, you can add other endpoints to your configuration file:
+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
{
@@ -137,10 +138,6 @@ The examples above have configured the "Default" remote service endpoint. You ma
}
````
-See the next section to learn how to use this new endpoint.
-
-### AddHttpClientProxies Method
-
`AddHttpClientProxies` method can get an additional parameter for the remote service name. Example:
````csharp
@@ -150,4 +147,19 @@ context.Services.AddHttpClientProxies(
);
````
-`remoteServiceName` parameter matches the service endpoint configured via `RemoteServiceOptions`. If the `BookStore` endpoint is not defined then it fallbacks to the `Default` endpoint.
\ No newline at end of file
+`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/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/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/Index.md b/docs/en/Index.md
index bd65ed5c7f..b1bccab0ea 100644
--- a/docs/en/Index.md
+++ b/docs/en/Index.md
@@ -6,25 +6,25 @@ 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 in progress and currently is very incomplete.
+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 applications, it's suggested to use the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which is feature rich, mature, maintained and up-to-date.
+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:
+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, use the following tutorials:
+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 being developed on GitHub. See [the source code](https://github.com/abpframework/abp).
+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.
\ No newline at end of file
+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/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