• 手动搭建ABP2.1.3 Zero——基础框架


    一、基础层搭建

    二、PM.Core

    三、PM.EntityFramework

    四、PM.Application

    五、PM.WebApi 

    六、PM.Web(MPA)

    七、PM.Web(SPA)

    八、单元测试

    一、基础层搭建

    1,创建一个空解决方案 

    2,层结构

    PM.Core[v:4.6]:类库

    PM.EntityFramework[v:4.6]:类库(引用PM.Core)

    PM.Application[v:4.6]:类库(引用PM.Core)

    PM.WebApi[v:4.6]:类库(引用PM.Application、PM.Core)

    PM.Web[v:4.6]:WebMvc5.X(引用PM.Core、PM.EntityFramework、PM.Application、PM.WebApi)

    PM.Test[v:4.6]:(引用PM.EntityFramework、PM.Core、PM.Application)

    二、PM.Core

    1,NuGet安装Abp.Zero2.1.3

    程序集引用:System.ComponentModel.DataAnnotations

    2,基本结构

    Authorization

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.MultiTenancy;
    using Abp.Zero.Configuration;
    
    namespace PM.Core.Authorization.Roles
    {
        public class PMRoleConfig
        {
            public static void Configure(IRoleManagementConfig roleManagementConfig)
            {
                //静态主机角色
                roleManagementConfig.StaticRoles.Add(new StaticRoleDefinition(
                    StaticRoleNames.Host.Admin
                    , MultiTenancySides.Host));
    
                //静态租户角色
                roleManagementConfig.StaticRoles.Add(new StaticRoleDefinition(
                    StaticRoleNames.Tenants.Admin,
                    MultiTenancySides.Tenant));
            }
        }
    }
    PMRoleConfig
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization.Roles;
    using PM.Core.Users;
    
    namespace PM.Core.Authorization.Roles
    {
        public class Role : AbpRole<User>
        {
    
        }
    }
    Role
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.Domain.Uow;
    using Abp.Runtime.Caching;
    using Abp.Zero.Configuration;
    using PM.Core.Users;
    
    namespace PM.Core.Authorization.Roles
    {
        public class RoleManager:AbpRoleManager<Role,User>
        {
            public RoleManager(
                RoleStore store, 
                IPermissionManager permissionManager,
                IRoleManagementConfig roleManagementConfig, 
                ICacheManager cacheManager, 
                IUnitOfWorkManager unitOfWorkManager)
                : base(store, 
                      permissionManager, 
                      roleManagementConfig, 
                      cacheManager, 
                      unitOfWorkManager)
            {
            }
        }
    }
    RoleManager
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization.Roles;
    using Abp.Authorization.Users;
    using Abp.Domain.Repositories;
    using PM.Core.Users;
    
    namespace PM.Core.Authorization.Roles
    {
        public class RoleStore:AbpRoleStore<Role,User>
        {
            public RoleStore(
                IRepository<Role> roleRepository, 
                IRepository<UserRole, long> userRoleRepository,
                IRepository<RolePermissionSetting, long> rolePermissionSettingRepository)
                : base(roleRepository, 
                      userRoleRepository, 
                      rolePermissionSettingRepository)
            {
            }
        }
    }
    RoleStore
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace PM.Core.Authorization.Roles
    {
        public class StaticRoleNames
        {
            public static class  Host
            {
                public const string Admin = "Admin";
            }
            public static class Tenants
            {
                public const string Admin = "Admin";
            }
        }
    }
    StaticRoleNames
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.Authorization.Users;
    using Abp.Configuration;
    using Abp.Domain.Repositories;
    using Abp.Domain.Uow;
    using Abp.IdentityFramework;
    using Abp.Localization;
    using Abp.Organizations;
    using Abp.Runtime.Caching;
    using PM.Core.Authorization.Roles;
    
    namespace PM.Core.Users
    {
        public class UserManager : AbpUserManager<Role, User>
        {
            public UserManager(
                UserStore userStore, 
                RoleManager roleManager,
                IPermissionManager permissionManager, 
                IUnitOfWorkManager unitOfWorkManager, 
                ICacheManager cacheManager,
                IRepository<OrganizationUnit, long> organizationUnitRepository,
                IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
                IOrganizationUnitSettings organizationUnitSettings, 
                ILocalizationManager localizationManager,
                IdentityEmailMessageService emailService, 
                ISettingManager settingManager,
                IUserTokenProviderAccessor userTokenProviderAccessor)
                : base(
                    userStore, 
                    roleManager, 
                    permissionManager, 
                    unitOfWorkManager, 
                    cacheManager, 
                    organizationUnitRepository,
                    userOrganizationUnitRepository, 
                    organizationUnitSettings, 
                    localizationManager, 
                    emailService,
                    settingManager, 
                    userTokenProviderAccessor)
            {
            }
        }
    }
    UserManager
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization.Users;
    using Abp.Domain.Repositories;
    using Abp.Domain.Uow;
    using PM.Core.Authorization.Roles;
    
    namespace PM.Core.Users
    {
        public class UserStore:AbpUserStore<Role,User>
        {
            public UserStore(
                IRepository<User, long> userRepository, 
                IRepository<UserLogin, long> userLoginRepository,
                IRepository<UserRole, long> userRoleRepository, 
                IRepository<Role> roleRepository,
                IRepository<UserPermissionSetting, long> userPermissionSettingRepository,
                IUnitOfWorkManager unitOfWorkManager, 
                IRepository<UserClaim, long> userClaimRepository)
                : base(
                    userRepository, 
                    userLoginRepository, 
                    userRoleRepository, 
                    roleRepository, 
                    userPermissionSettingRepository,
                    unitOfWorkManager, 
                    userClaimRepository)
            {
            }
        }
    }
    UserStore
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.Authorization.Users;
    using Abp.Configuration;
    using Abp.Configuration.Startup;
    using Abp.Dependency;
    using Abp.Domain.Repositories;
    using Abp.Domain.Uow;
    using Abp.Zero.Configuration;
    using PM.Core.Authorization.Roles;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Core.Authorization
    {
        public class LogInManager : AbpLogInManager<Tenant,Role,User>
        {
            public LogInManager(
                UserManager userManager, 
                IMultiTenancyConfig multiTenancyConfig,
                IRepository<Tenant> tenantRepository, 
                IUnitOfWorkManager unitOfWorkManager, 
                ISettingManager settingManager,
                IRepository<UserLoginAttempt, long> userLoginAttemptRepository, 
                IUserManagementConfig userManagementConfig,
                IIocResolver iocResolver, 
                RoleManager roleManager)
                : base(
                    userManager, 
                    multiTenancyConfig, 
                    tenantRepository, 
                    unitOfWorkManager, 
                    settingManager,
                    userLoginAttemptRepository, 
                    userManagementConfig, 
                    iocResolver, 
                    roleManager)
            {
            }
        }
    }
    LogInManager
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Users;
    using PM.Core.Authorization.Roles;
    using PM.Core.Users;
    
    namespace PM.Core.Authorization
    {
        public class PermissionChecker:PermissionChecker<Role,User>
        {
            public PermissionChecker(UserManager userManager) : base(userManager)
            {
            }
        }
    }
    PermissionChecker
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace PM.Core.Authorization
    {
        public class PermisstionNames
        {
            public const string Pages_Tenants = "Pages.Tenants";
            public const string Pages_Users = "Pages.Users";
            public const string Pages_Roles = "Pages.Roles";
        }
    }
    PermisstionNames
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Localization;
    using Abp.Localization.Sources;
    using Abp.MultiTenancy;
    
    namespace PM.Core.Authorization
    {
        public class PMProjectNameAuthorizationProvider: AuthorizationProvider
        {
            public override void SetPermissions(IPermissionDefinitionContext context)
            {
    
                context.CreatePermission(PermisstionNames.Pages_Users, L("Users"));
                context.CreatePermission(PermisstionNames.Pages_Roles, L("Roles"));
                context.CreatePermission(PermisstionNames.Pages_Tenants, L("Tenants"),multiTenancySides:MultiTenancySides.Host);
    
            }
    
            private static ILocalizableString L(string name)
            {
                return new LocalizableString(name, PMProjectNameConsts.LocalizationSourceName);
            }
    
        }
    }
    PMProjectNameAuthorizationProvider
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization.Users;
    using Abp.Extensions;
    using Microsoft.AspNet.Identity;
    
    namespace PM.Core.Users
    {
        public class User:AbpUser<User>
        {
            public const string DefaultPassword = "123qwe";
    
            /// <summary>
            /// 创建随机密码
            /// </summary>
            /// <returns></returns>
            public static string CreateRandomPassword()
            {
                //截断16位
                return Guid.NewGuid().ToString("N").Truncate(16);
            }
    
            public static User CreateTenantAdminUser(int tenantId, string emailAddress, string password)
            {
                return new User()
                {
                    TenantId = tenantId,
                    UserName = AdminUserName,
                    Name = AdminUserName,
                    Surname = AdminUserName,
                    EmailAddress = emailAddress,
                    Password = new PasswordHasher().HashPassword(password),
                    IsEmailConfirmed = true,
                    IsActive = true
                };
            }
    
        }
    }
    User

    Configuration

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace PM.Core.Configuration
    {
        public class PMSettingNames
        {
            public const string UiTheme = "App.UiTheme";
        }
    }
    PMSettingNames
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Configuration;
    
    namespace PM.Core.Configuration
    {
        public class PMSettingProvider:SettingProvider
        {
            public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
            {
                return new[]
                {
                    new SettingDefinition(PMSettingNames.UiTheme, "red",
                        scopes: SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User,
                        isVisibleToClients: true)
                };
            }
        }
    }
    PMSettingProvider

    Editions

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Editions;
    using Abp.Application.Features;
    using Abp.Domain.Repositories;
    
    namespace PM.Core.Editions
    {
        public class EditionManager:AbpEditionManager
        {
            public const string DefaultEditionName = "Standard";
    
            public EditionManager(
                IRepository<Edition> editionRepository, 
                IAbpZeroFeatureValueStore featureValueStore)
                : base(editionRepository, 
                      featureValueStore)
            {
            }
        }
    }
    EditionManager

    Features

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Features;
    using Abp.Domain.Repositories;
    using Abp.Domain.Uow;
    using Abp.MultiTenancy;
    using Abp.Runtime.Caching;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Core.Features
    {
        public class FeaturesValueStore:AbpFeatureValueStore<Tenant,User>
        {
            public FeaturesValueStore(
                ICacheManager cacheManager,
                IRepository<TenantFeatureSetting, long> tenantFeatureRepository, 
                IRepository<Tenant> tenantRepository,
                IRepository<EditionFeatureSetting, long> editionFeatureRepository, 
                IFeatureManager featureManager,
                IUnitOfWorkManager unitOfWorkManager)
                : base(
                    cacheManager, 
                    tenantFeatureRepository, 
                    tenantRepository, 
                    editionFeatureRepository, 
                    featureManager,
                    unitOfWorkManager)
            {
            }
        }
    }
    FeaturesValueStore

    Localization

    <?xml version="1.0" encoding="utf-8" ?>
    <localizationDictionary culture="zh-CN">
      <texts>
        <text name="Users" value="用户"/>
        <text name="Roles" value="角色"/>
        <text name="Tenants" value="租户"/>
      </texts>
    </localizationDictionary>
    PMProjectName-zh-CN.xml
    <?xml version="1.0" encoding="utf-8" ?>
    <localizationDictionary culture="en">
      <texts>
        <text name="Users" value="Users"/>
        <text name="Roles" value="Roles"/>
        <text name="Tenants" value="Tenants"/>
      </texts>
    </localizationDictionary>
    PMProjectName.xml

    MultiTenant

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.MultiTenancy;
    using PM.Core.Users;
    
    namespace PM.Core.MultiTenant
    {
        public class Tenant:AbpTenant<User>
        {
    
        }
    }
    Tenant
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Editions;
    using Abp.Application.Features;
    using Abp.Domain.Repositories;
    using Abp.MultiTenancy;
    using PM.Core.Users;
    
    namespace PM.Core.MultiTenant
    {
        public class TenantManager:AbpTenantManager<Tenant,User>
        {
            public TenantManager(
                IRepository<Tenant> tenantRepository,
                IRepository<TenantFeatureSetting, long> tenantFeatureRepository, 
                AbpEditionManager editionManager,
                IAbpZeroFeatureValueStore featureValueStore)
                : base(tenantRepository, 
                      tenantFeatureRepository, 
                      editionManager, 
                      featureValueStore)
            {
            }
        }
    }
    TenantManager

    Validation

    using Abp.Extensions;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    
    namespace PM.Core.Validation
    {
        public class ValidationHelper
        {
            public const string EmailRegex = @"^w+([-+.']w+)*@w+([-.]w+)*.w+([-.]w+)*$";
    
            public static bool IsEmail(string value)
            {
                if (value.IsNullOrEmpty())
                {
                    return false;
                }
    
                var regex = new Regex(EmailRegex);
                return regex.IsMatch(value);
            }
        }
    }
    ValidationHelper

    PMProjectNameConsts 公共常量类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace PM.Core
    {
        public class PMProjectNameConsts
        {
            public const string LocalizationSourceName = "PMProjectName";
            public const bool MultiTenantEnabled = true;
        }
    }
    PMProjectNameConsts

    PMVersionHepler 版本帮助类

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Reflection.Extensions;
    
    namespace PM.Core
    {
        /// <summary>
        /// 应用版本中心
        /// </summary>
        public class PMVersionHepler
        {
            /// <summary>
            /// 获取应用程序当前版本
            /// 显示在网页中
            /// </summary>
            public const string Version = "1.0.0.0";
    
            /// <summary>
            /// 获取应用程序最后一次发布的时间
            /// 它显示在网页中
            /// </summary>
            public static DateTime ReleaseDate
            {
                get { return new FileInfo(typeof(PMVersionHepler).GetAssembly().Location).LastWriteTime; }
            }
    
        }
    }
    PMVersionHepler

    PMCoreModule模块类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Localization.Dictionaries;
    using Abp.Localization.Dictionaries.Xml;
    using Abp.Modules;
    using Abp.Zero;
    using Abp.Zero.Configuration;
    using PM.Core.Authorization;
    using PM.Core.Authorization.Roles;
    using PM.Core.Configuration;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Core
    {
        [DependsOn(typeof(AbpZeroCoreModule))]
        public class PMCoreModule:AbpModule
        {
            public override void PreInitialize()
            {
                //如果当前用户未登录,请设置为true以启用保存审核日志。默认值:
                Configuration.Auditing.IsEnabledForAnonymousUsers = true;
    
                //声明实体类型
                Configuration.Modules.Zero().EntityTypes.Tenant = typeof (Tenant);
                Configuration.Modules.Zero().EntityTypes.Role = typeof (Role);
                Configuration.Modules.Zero().EntityTypes.User = typeof (User);
    
                //开启多租户
                Configuration.MultiTenancy.IsEnabled = PMProjectNameConsts.MultiTenantEnabled;
    
                //添加删除本地化源
                Configuration.Localization.Sources.Add(
                    new DictionaryBasedLocalizationSource(PMProjectNameConsts.LocalizationSourceName,
                        new XmlEmbeddedFileLocalizationDictionaryProvider(Assembly.GetExecutingAssembly(),
                            "PM.Localization.Source")));
    
                //设置静态角色
                PMRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
    
                //初始化权限
                Configuration.Authorization.Providers.Add<PMProjectNameAuthorizationProvider>();
    
                //初始化设置
                Configuration.Settings.Providers.Add<PMSettingProvider>();
    
            }
    
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
            }
        }
    }
    PMCoreModule

    三、PM.EntityFramework

    1,NuGet安装Abp.Zero2.1.3、Abp.Zero.EntityFramework2.13

    2,基本结构

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Domain.Entities;
    using Abp.EntityFramework;
    using Abp.EntityFramework.Repositories;
    
    namespace PM.EntityFramework.EntityFramework.Repositories
    {
        public class PMRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<PMDBContext, TEntity, TPrimaryKey>
            where TEntity:class,IEntity<TPrimaryKey>
        {
            public PMRepositoryBase(IDbContextProvider<PMDBContext> dbContextProvider) : base(dbContextProvider)
            {
            }
    
            //为所有存储库添加常用方法
        }
    
        public class PMRepositoryBase<TEntity> : PMRepositoryBase<TEntity, int>
            where TEntity : class, IEntity<int>
        {
            public PMRepositoryBase(IDbContextProvider<PMDBContext> dbContextProvider) : base(dbContextProvider)
            {
            }
            //不要在这里添加任何方法,添加到上面的类(因为它继承它)
        }
    
    }
    PMRepositoryBase
    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Zero.EntityFramework;
    using PM.Core.Authorization.Roles;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.EntityFramework.EntityFramework
    {
        public class PMDBContext:AbpZeroDbContext<Tenant,Role,User>
        {
            /// <summary>
            /// 将“默认”设置为基类可帮助我们在Package Manager Console上执行迁移命令时使用。
            /// 但是,在运行EF的Migrate.exe时可能会导致问题。 如果要在命令行上应用迁移,请不要将连接字符串名称传递给基类。 ABP工作方式。
            /// </summary>
            public PMDBContext() : base("Default")
            {
            }
    
            /// <summary>
            /// ABP使用此构造函数传递PMDBContext.PreInitialize中定义的连接字符串。
            /// 注意,实际上你不会直接创建一个PMDBContext的实例,因为ABP自动处理它。
            /// </summary>
            /// <param name="nameOrnameOrConnectionString"></param>
            public PMDBContext(string nameOrnameOrConnectionString) : base(nameOrnameOrConnectionString)
            {
            }
    
            /// <summary>
            /// 这个构造函数用于测试
            /// </summary>
            /// <param name="existingConnection"></param>
            public PMDBContext(DbConnection existingConnection) : base(existingConnection,false)
            {
            }
    
            public PMDBContext(DbConnection existingConnection, bool contextOwnsConnection)
                : base(existingConnection, contextOwnsConnection)
            {
            }
    
        }
    }
    PMDBContext
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Editions;
    using PM.Core.Editions;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
    
        /// <summary>
        /// 默认版本创建者
        /// </summary>
        public class DefaultEditionsCreator
        {
            private readonly PMDBContext _context;
    
            public DefaultEditionsCreator(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                CreateEdtions();
            }
    
            private void CreateEdtions()
            {
                var defaultEdtion = _context.Editions.FirstOrDefault(e => e.Name == EditionManager.DefaultEditionName);
                if (defaultEdtion == null)
                {
                    defaultEdtion = new Edition()
                    {
                        Name = EditionManager.DefaultEditionName,
                        DisplayName = EditionManager.DefaultEditionName
                    };
                    _context.Editions.Add(defaultEdtion);
                    _context.SaveChanges();
    
                    //TODO:如果需要,可以在标准版中添加所需的功能!
                }
            }
    
        }
    }
    DefaultEditionsCreator
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Localization;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 默认语言创建者
        /// </summary>
        public class DefaultLanguagesCreator
        {
            public static List<ApplicationLanguage> InitialLanguages { get; private set; } 
            private readonly PMDBContext _context;
    
            static DefaultLanguagesCreator()
            {
                InitialLanguages = new List<ApplicationLanguage>
                {
                    new ApplicationLanguage(null, "en", "English", "famfamfam-flags gb"),
                    new ApplicationLanguage(null, "tr", "Türkçe", "famfamfam-flags tr"),
                    new ApplicationLanguage(null, "zh-CN", "简体中文", "famfamfam-flags cn"),
                    new ApplicationLanguage(null, "pt-BR", "Português-BR", "famfamfam-flags br"),
                    new ApplicationLanguage(null, "es", "Español", "famfamfam-flags es"),
                    new ApplicationLanguage(null, "fr", "Français", "famfamfam-flags fr"),
                    new ApplicationLanguage(null, "it", "Italiano", "famfamfam-flags it"),
                    new ApplicationLanguage(null, "ja", "日本語", "famfamfam-flags jp"),
                    new ApplicationLanguage(null, "nl-NL", "Nederlands", "famfamfam-flags nl"),
                    new ApplicationLanguage(null, "lt", "Lietuvos", "famfamfam-flags lt"),
                    new ApplicationLanguage(null, "vn", "Vietnamese", "famfamfam-flags vn")
                };
            }
    
            public DefaultLanguagesCreator(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                CreateLanguages();
            }
    
            private void CreateLanguages()
            {
                foreach (var applicationLanguage in InitialLanguages)
                {
                    AddLanguageIfNotExists(applicationLanguage);
                }
            }
    
            private void AddLanguageIfNotExists(ApplicationLanguage language)
            {
                if (_context.Languages.Any(l => l.TenantId == language.TenantId && l.Name == language.Name))
                {
                    return;
                }
                _context.Languages.Add(language);
                _context.SaveChanges();
            }
    
    
    
        }
    }
    DefaultLanguagesCreator
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Configuration;
    using Abp.Localization;
    using Abp.Net.Mail;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 默认设置创建者
        /// </summary>
        public class DefaultSettingsCreator
        {
            private readonly PMDBContext _context;
    
            public DefaultSettingsCreator(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                //邮箱
                AddSettingIfNotExists(EmailSettingNames.DefaultFromAddress, "qq962410314@163.com");
                AddSettingIfNotExists(EmailSettingNames.DefaultFromDisplayName, "qq962410314@163.com");
    
                //语言
                AddSettingIfNotExists(LocalizationSettingNames.DefaultLanguage, "zh-CN");
            }
    
            private void AddSettingIfNotExists(string name, string value, int? tenantId = null)
            {
                if (_context.Settings.Any(s => s.Name == name && s.TenantId == tenantId && s.UserId == null))
                {
                    return;
                }
                _context.Settings.Add(new Setting(tenantId, null, name, value));
                _context.SaveChanges();
            }
    
    
        }
    }
    DefaultSettingsCreator
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using PM.Core.MultiTenant;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 默认租户创建者
        /// </summary>
        public class DefaultTenantCreator
        {
            private readonly PMDBContext _context;
    
            public DefaultTenantCreator(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                CreateUserAndRoles();
            }
    
            private void CreateUserAndRoles()
            {
                //默认租户
                var defaultTenant = _context.Tenants.FirstOrDefault(t => t.TenancyName == Tenant.DefaultTenantName);
                if (defaultTenant == null)
                {
                    _context.Tenants.Add(new Tenant()
                    {
                        TenancyName = Tenant.DefaultTenantName,
                        Name = Tenant.DefaultTenantName
                    });
                    _context.SaveChanges();
                }
    
            }
    
        }
    }
    DefaultTenantCreator
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.Authorization.Users;
    using Abp.MultiTenancy;
    using Microsoft.AspNet.Identity;
    using PM.Core.Authorization;
    using PM.Core.Authorization.Roles;
    using PM.Core.Users;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 主机admin创建者
        /// </summary>
        public class HostRoleAndUserCreator
        {
            private readonly PMDBContext _context;
    
            public HostRoleAndUserCreator(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                CreateHostRoleAndUsers();
            }
    
            private void CreateHostRoleAndUsers()
            {
                //主机角色
                var adminRoleForHost= _context.Roles.FirstOrDefault(r => r.TenantId == null && r.Name == StaticRoleNames.Host.Admin);
                if (adminRoleForHost == null)
                {
                    adminRoleForHost = _context.Roles.Add(new Role()
                    {
                        Name = StaticRoleNames.Host.Admin,
                        DisplayName = StaticRoleNames.Host.Admin,
                        IsStatic = true
                    });
                    _context.SaveChanges();
    
                    //授予所有租户权限
                    var permisstions = PermissionFinder.GetAllPermissions(new PMProjectNameAuthorizationProvider())
                        .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Host))
                        .ToList();
                    foreach (var permisstion in permisstions)
                    {
                        _context.Permissions.Add(new RolePermissionSetting()
                        {
                            Name = permisstion.Name,
                            IsGranted = true,
                            RoleId = adminRoleForHost.Id
                        });
                    }
                    _context.SaveChanges();
                }
    
                //主机admin
                var adminUserForHost =
                    _context.Users.FirstOrDefault(u => u.TenantId == null && u.UserName == User.AdminUserName);
                if (adminUserForHost == null)
                {
                    adminUserForHost = _context.Users.Add(new User()
                    {
                        UserName = User.AdminUserName,
                        Name = "System",
                        Surname = "Administrator",
                        EmailAddress = "qq962410314@163.com",
                        IsEmailConfirmed = true,
                        Password = new PasswordHasher().HashPassword(User.DefaultPassword)
                    });
    
                    _context.SaveChanges();
                    _context.UserRoles.Add(new UserRole(null, adminUserForHost.Id, adminRoleForHost.Id));
                    _context.SaveChanges();
                }
    
    
            }
    
        }
    }
    HostRoleAndUserCreator
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using EntityFramework.DynamicFilters;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 初始化主机数据库提供者
        /// </summary>
        public class InitialHostDbBuilder
        {
            private readonly PMDBContext _context;
    
            public InitialHostDbBuilder(PMDBContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                //禁用所有过滤器
                _context.DisableAllFilters();
    
                new DefaultEditionsCreator(_context).Create();
                new DefaultLanguagesCreator(_context).Create();
                new HostRoleAndUserCreator(_context).Create();
                new DefaultSettingsCreator(_context).Create();
    
            }
    
        }
    }
    InitialHostDbBuilder
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.Authorization.Users;
    using Abp.MultiTenancy;
    using PM.Core.Authorization;
    using PM.Core.Authorization.Roles;
    using PM.Core.Users;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations.SeedData
    {
        /// <summary>
        /// 租户admin创建者
        /// </summary>
        public class TenantRoleAndUserBuilder
        {
            private readonly PMDBContext _context;
            private readonly int _tenantId;
    
            public TenantRoleAndUserBuilder(PMDBContext context, int tenantId)
            {
                _context = context;
                _tenantId = tenantId;
            }
    
            public void Create()
            {
                CreateRolesAndUsers();
            }
    
            private void CreateRolesAndUsers()
            {
    
                //租户角色
                var adminRole =
                    _context.Roles.FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.Admin);
                if (adminRole==null)
                {
                    adminRole =
                        _context.Roles.Add(new Role(_tenantId, StaticRoleNames.Tenants.Admin, StaticRoleNames.Tenants.Admin)
                        {
                            IsStatic = true
                        });
                    _context.SaveChanges();
    
                    //授予管理员角色的所有权限
                    var permisstions = PermissionFinder.GetAllPermissions(new PMProjectNameAuthorizationProvider())
                        .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Tenant))
                        .ToList();
                    foreach (var permisstion in permisstions)
                    {
                        _context.Permissions.Add(new RolePermissionSetting()
                        {
                            TenantId = _tenantId,
                            Name = permisstion.Name,
                            IsGranted = true,
                            RoleId = adminRole.Id
                        });
                    }
                    _context.SaveChanges();
                }
    
                //租户admin
                var adminUser =
                    _context.Users.FirstOrDefault(u => u.TenantId == _tenantId && u.UserName == User.AdminUserName);
                if (adminUser == null)
                {
                    adminUser = User.CreateTenantAdminUser(_tenantId, "qq962410314@163.com", User.DefaultPassword);
                    adminUser.IsEmailConfirmed = true;
                    adminUser.IsActive = true;
    
                    _context.Users.Add(adminUser);
                    _context.SaveChanges();
    
                    _context.UserRoles.Add(new UserRole(_tenantId, adminUser.Id, adminRole.Id));
                    _context.SaveChanges();
                }
            }
        }
    }
    TenantRoleAndUserBuilder
    namespace PM.EntityFramework.Migrations
    {
        using System;
        using System.Collections.Generic;
        using System.Data.Entity.Infrastructure.Annotations;
        using System.Data.Entity.Migrations;
        
        public partial class init : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.AbpAuditLogs",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(),
                            ServiceName = c.String(maxLength: 256),
                            MethodName = c.String(maxLength: 256),
                            Parameters = c.String(maxLength: 1024),
                            ExecutionTime = c.DateTime(nullable: false),
                            ExecutionDuration = c.Int(nullable: false),
                            ClientIpAddress = c.String(maxLength: 64),
                            ClientName = c.String(maxLength: 128),
                            BrowserInfo = c.String(maxLength: 256),
                            Exception = c.String(maxLength: 2000),
                            ImpersonatorUserId = c.Long(),
                            ImpersonatorTenantId = c.Int(),
                            CustomData = c.String(maxLength: 2000),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_AuditLog_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpBackgroundJobs",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            JobType = c.String(nullable: false, maxLength: 512),
                            JobArgs = c.String(nullable: false),
                            TryCount = c.Short(nullable: false),
                            NextTryTime = c.DateTime(nullable: false),
                            LastTryTime = c.DateTime(),
                            IsAbandoned = c.Boolean(nullable: false),
                            Priority = c.Byte(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        })
                    .PrimaryKey(t => t.Id)
                    .Index(t => new { t.IsAbandoned, t.NextTryTime });
                
                CreateTable(
                    "dbo.AbpFeatures",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            Name = c.String(nullable: false, maxLength: 128),
                            Value = c.String(nullable: false, maxLength: 2000),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                            EditionId = c.Int(),
                            TenantId = c.Int(),
                            Discriminator = c.String(nullable: false, maxLength: 128),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_TenantFeatureSetting_MustHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpEditions", t => t.EditionId, cascadeDelete: true)
                    .Index(t => t.EditionId);
                
                CreateTable(
                    "dbo.AbpEditions",
                    c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            Name = c.String(nullable: false, maxLength: 32),
                            DisplayName = c.String(nullable: false, maxLength: 64),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Edition_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpLanguages",
                    c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            TenantId = c.Int(),
                            Name = c.String(nullable: false, maxLength: 10),
                            DisplayName = c.String(nullable: false, maxLength: 64),
                            Icon = c.String(maxLength: 128),
                            IsDisabled = c.Boolean(nullable: false),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_ApplicationLanguage_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_ApplicationLanguage_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpLanguageTexts",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            LanguageName = c.String(nullable: false, maxLength: 10),
                            Source = c.String(nullable: false, maxLength: 128),
                            Key = c.String(nullable: false, maxLength: 256),
                            Value = c.String(nullable: false),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_ApplicationLanguageText_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpNotifications",
                    c => new
                        {
                            Id = c.Guid(nullable: false),
                            NotificationName = c.String(nullable: false, maxLength: 96),
                            Data = c.String(),
                            DataTypeName = c.String(maxLength: 512),
                            EntityTypeName = c.String(maxLength: 250),
                            EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
                            EntityId = c.String(maxLength: 96),
                            Severity = c.Byte(nullable: false),
                            UserIds = c.String(),
                            ExcludedUserIds = c.String(),
                            TenantIds = c.String(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpNotificationSubscriptions",
                    c => new
                        {
                            Id = c.Guid(nullable: false),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            NotificationName = c.String(maxLength: 96),
                            EntityTypeName = c.String(maxLength: 250),
                            EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
                            EntityId = c.String(maxLength: 96),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_NotificationSubscriptionInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .Index(t => new { t.NotificationName, t.EntityTypeName, t.EntityId, t.UserId });
                
                CreateTable(
                    "dbo.AbpOrganizationUnits",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            ParentId = c.Long(),
                            Code = c.String(nullable: false, maxLength: 95),
                            DisplayName = c.String(nullable: false, maxLength: 128),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_OrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_OrganizationUnit_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpOrganizationUnits", t => t.ParentId)
                    .Index(t => t.ParentId);
                
                CreateTable(
                    "dbo.AbpPermissions",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            Name = c.String(nullable: false, maxLength: 128),
                            IsGranted = c.Boolean(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                            RoleId = c.Int(),
                            UserId = c.Long(),
                            Discriminator = c.String(nullable: false, maxLength: 128),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_PermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_RolePermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_UserPermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
                    .ForeignKey("dbo.AbpRoles", t => t.RoleId, cascadeDelete: true)
                    .Index(t => t.RoleId)
                    .Index(t => t.UserId);
                
                CreateTable(
                    "dbo.AbpRoles",
                    c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            Description = c.String(),
                            TenantId = c.Int(),
                            Name = c.String(nullable: false, maxLength: 32),
                            DisplayName = c.String(nullable: false, maxLength: 64),
                            IsStatic = c.Boolean(nullable: false),
                            IsDefault = c.Boolean(nullable: false),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Role_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_Role_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
                    .ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
                    .ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
                    .Index(t => t.DeleterUserId)
                    .Index(t => t.LastModifierUserId)
                    .Index(t => t.CreatorUserId);
                
                CreateTable(
                    "dbo.AbpUsers",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            AuthenticationSource = c.String(maxLength: 64),
                            UserName = c.String(nullable: false, maxLength: 32),
                            TenantId = c.Int(),
                            EmailAddress = c.String(nullable: false, maxLength: 256),
                            Name = c.String(nullable: false, maxLength: 32),
                            Surname = c.String(nullable: false, maxLength: 32),
                            Password = c.String(nullable: false, maxLength: 128),
                            EmailConfirmationCode = c.String(maxLength: 328),
                            PasswordResetCode = c.String(maxLength: 328),
                            LockoutEndDateUtc = c.DateTime(),
                            AccessFailedCount = c.Int(nullable: false),
                            IsLockoutEnabled = c.Boolean(nullable: false),
                            PhoneNumber = c.String(),
                            IsPhoneNumberConfirmed = c.Boolean(nullable: false),
                            SecurityStamp = c.String(),
                            IsTwoFactorEnabled = c.Boolean(nullable: false),
                            IsEmailConfirmed = c.Boolean(nullable: false),
                            IsActive = c.Boolean(nullable: false),
                            LastLoginTime = c.DateTime(),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_User_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_User_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
                    .ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
                    .ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
                    .Index(t => t.DeleterUserId)
                    .Index(t => t.LastModifierUserId)
                    .Index(t => t.CreatorUserId);
                
                CreateTable(
                    "dbo.AbpUserClaims",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            ClaimType = c.String(),
                            ClaimValue = c.String(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserClaim_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
                    .Index(t => t.UserId);
                
                CreateTable(
                    "dbo.AbpUserLogins",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            LoginProvider = c.String(nullable: false, maxLength: 128),
                            ProviderKey = c.String(nullable: false, maxLength: 256),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserLogin_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
                    .Index(t => t.UserId);
                
                CreateTable(
                    "dbo.AbpUserRoles",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            RoleId = c.Int(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserRole_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
                    .Index(t => t.UserId);
                
                CreateTable(
                    "dbo.AbpSettings",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(),
                            Name = c.String(nullable: false, maxLength: 256),
                            Value = c.String(maxLength: 2000),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Setting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.UserId)
                    .Index(t => t.UserId);
                
                CreateTable(
                    "dbo.AbpTenantNotifications",
                    c => new
                        {
                            Id = c.Guid(nullable: false),
                            TenantId = c.Int(),
                            NotificationName = c.String(nullable: false, maxLength: 96),
                            Data = c.String(),
                            DataTypeName = c.String(maxLength: 512),
                            EntityTypeName = c.String(maxLength: 250),
                            EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
                            EntityId = c.String(maxLength: 96),
                            Severity = c.Byte(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_TenantNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpTenants",
                    c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            EditionId = c.Int(),
                            Name = c.String(nullable: false, maxLength: 128),
                            TenancyName = c.String(nullable: false, maxLength: 64),
                            ConnectionString = c.String(maxLength: 1024),
                            IsActive = c.Boolean(nullable: false),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Tenant_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
                    .ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
                    .ForeignKey("dbo.AbpEditions", t => t.EditionId)
                    .ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
                    .Index(t => t.EditionId)
                    .Index(t => t.DeleterUserId)
                    .Index(t => t.LastModifierUserId)
                    .Index(t => t.CreatorUserId);
                
                CreateTable(
                    "dbo.AbpUserAccounts",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            UserLinkId = c.Long(),
                            UserName = c.String(),
                            EmailAddress = c.String(),
                            LastLoginTime = c.DateTime(),
                            IsDeleted = c.Boolean(nullable: false),
                            DeleterUserId = c.Long(),
                            DeletionTime = c.DateTime(),
                            LastModificationTime = c.DateTime(),
                            LastModifierUserId = c.Long(),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserAccount_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
                CreateTable(
                    "dbo.AbpUserLoginAttempts",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            TenancyName = c.String(maxLength: 64),
                            UserId = c.Long(),
                            UserNameOrEmailAddress = c.String(maxLength: 255),
                            ClientIpAddress = c.String(maxLength: 64),
                            ClientName = c.String(maxLength: 128),
                            BrowserInfo = c.String(maxLength: 256),
                            Result = c.Byte(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserLoginAttempt_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .Index(t => new { t.UserId, t.TenantId })
                    .Index(t => new { t.TenancyName, t.UserNameOrEmailAddress, t.Result });
                
                CreateTable(
                    "dbo.AbpUserNotifications",
                    c => new
                        {
                            Id = c.Guid(nullable: false),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            TenantNotificationId = c.Guid(nullable: false),
                            State = c.Int(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id)
                    .Index(t => new { t.UserId, t.State, t.CreationTime });
                
                CreateTable(
                    "dbo.AbpUserOrganizationUnits",
                    c => new
                        {
                            Id = c.Long(nullable: false, identity: true),
                            TenantId = c.Int(),
                            UserId = c.Long(nullable: false),
                            OrganizationUnitId = c.Long(nullable: false),
                            CreationTime = c.DateTime(nullable: false),
                            CreatorUserId = c.Long(),
                        },
                    annotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserOrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    })
                    .PrimaryKey(t => t.Id);
                
            }
            
            public override void Down()
            {
                DropForeignKey("dbo.AbpTenants", "LastModifierUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpTenants", "EditionId", "dbo.AbpEditions");
                DropForeignKey("dbo.AbpTenants", "DeleterUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpTenants", "CreatorUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpPermissions", "RoleId", "dbo.AbpRoles");
                DropForeignKey("dbo.AbpRoles", "LastModifierUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpRoles", "DeleterUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpRoles", "CreatorUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpSettings", "UserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUserRoles", "UserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpPermissions", "UserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUserLogins", "UserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUsers", "LastModifierUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUsers", "DeleterUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUsers", "CreatorUserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpUserClaims", "UserId", "dbo.AbpUsers");
                DropForeignKey("dbo.AbpOrganizationUnits", "ParentId", "dbo.AbpOrganizationUnits");
                DropForeignKey("dbo.AbpFeatures", "EditionId", "dbo.AbpEditions");
                DropIndex("dbo.AbpUserNotifications", new[] { "UserId", "State", "CreationTime" });
                DropIndex("dbo.AbpUserLoginAttempts", new[] { "TenancyName", "UserNameOrEmailAddress", "Result" });
                DropIndex("dbo.AbpUserLoginAttempts", new[] { "UserId", "TenantId" });
                DropIndex("dbo.AbpTenants", new[] { "CreatorUserId" });
                DropIndex("dbo.AbpTenants", new[] { "LastModifierUserId" });
                DropIndex("dbo.AbpTenants", new[] { "DeleterUserId" });
                DropIndex("dbo.AbpTenants", new[] { "EditionId" });
                DropIndex("dbo.AbpSettings", new[] { "UserId" });
                DropIndex("dbo.AbpUserRoles", new[] { "UserId" });
                DropIndex("dbo.AbpUserLogins", new[] { "UserId" });
                DropIndex("dbo.AbpUserClaims", new[] { "UserId" });
                DropIndex("dbo.AbpUsers", new[] { "CreatorUserId" });
                DropIndex("dbo.AbpUsers", new[] { "LastModifierUserId" });
                DropIndex("dbo.AbpUsers", new[] { "DeleterUserId" });
                DropIndex("dbo.AbpRoles", new[] { "CreatorUserId" });
                DropIndex("dbo.AbpRoles", new[] { "LastModifierUserId" });
                DropIndex("dbo.AbpRoles", new[] { "DeleterUserId" });
                DropIndex("dbo.AbpPermissions", new[] { "UserId" });
                DropIndex("dbo.AbpPermissions", new[] { "RoleId" });
                DropIndex("dbo.AbpOrganizationUnits", new[] { "ParentId" });
                DropIndex("dbo.AbpNotificationSubscriptions", new[] { "NotificationName", "EntityTypeName", "EntityId", "UserId" });
                DropIndex("dbo.AbpFeatures", new[] { "EditionId" });
                DropIndex("dbo.AbpBackgroundJobs", new[] { "IsAbandoned", "NextTryTime" });
                DropTable("dbo.AbpUserOrganizationUnits",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserOrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserNotifications",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserLoginAttempts",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserLoginAttempt_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserAccounts",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserAccount_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpTenants",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Tenant_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpTenantNotifications",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_TenantNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpSettings",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Setting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserRoles",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserRole_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserLogins",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserLogin_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUserClaims",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_UserClaim_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpUsers",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_User_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_User_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpRoles",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Role_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_Role_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpPermissions",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_PermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_RolePermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_UserPermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpOrganizationUnits",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_OrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_OrganizationUnit_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpNotificationSubscriptions",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_NotificationSubscriptionInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpNotifications");
                DropTable("dbo.AbpLanguageTexts",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_ApplicationLanguageText_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpLanguages",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_ApplicationLanguage_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                        { "DynamicFilter_ApplicationLanguage_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpEditions",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_Edition_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpFeatures",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_TenantFeatureSetting_MustHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
                DropTable("dbo.AbpBackgroundJobs");
                DropTable("dbo.AbpAuditLogs",
                    removedAnnotations: new Dictionary<string, object>
                    {
                        { "DynamicFilter_AuditLog_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
                    });
            }
        }
    }
    init
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Dependency;
    using Abp.Domain.Uow;
    using Abp.MultiTenancy;
    using Abp.Zero.EntityFramework;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework.Migrations
    {
        /// <summary>
        /// 执行数据库迁移
        /// </summary>
        public class AbpZeroDbMigrator : AbpZeroDbMigrator<PMDBContext, Configuration>
        {
            public AbpZeroDbMigrator(IUnitOfWorkManager unitOfWorkManager,
                IDbPerTenantConnectionStringResolver connectionStringResolver, IIocResolver iocResolver)
                : base(unitOfWorkManager, connectionStringResolver, iocResolver)
            {
            }
        }
    }
    AbpZeroDbMigrator
    using Abp.MultiTenancy;
    using Abp.Zero.EntityFramework;
    using EntityFramework.DynamicFilters;
    using PM.EntityFramework.Migrations.SeedData;
    
    namespace PM.EntityFramework.Migrations
    {
        using System;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        public sealed class Configuration : DbMigrationsConfiguration<PM.EntityFramework.EntityFramework.PMDBContext>,IMultiTenantSeed
        {
            public AbpTenantBase Tenant { get; set; }
    
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
                ContextKey = "PM";
            }
    
            //Seed() 方法会在你每次你执行 Update-Database 指令时被呼叫一次
            protected override void Seed(PM.EntityFramework.EntityFramework.PMDBContext context)
            {
                //禁用所有过滤
                context.DisableAllFilters();
                if (Tenant == null)
                {
                    //主机种子
                    new InitialHostDbBuilder(context).Create();
    
                    //默认租户种子
                    new DefaultTenantCreator(context).Create();
                    new TenantRoleAndUserBuilder(context, 1).Create();
                }
                else
                {
                    //您可以为租户数据库添加种子并使用租户属性...
                }
                context.SaveChanges();
            }
    
        }
    }
    Configuration
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Modules;
    using Abp.Zero.EntityFramework;
    using PM.Core;
    using PM.EntityFramework.EntityFramework;
    
    namespace PM.EntityFramework
    {
        [DependsOn(typeof(PMCoreModule),typeof(AbpZeroEntityFrameworkModule))]
        public class PMDataModule:AbpModule
        {
            public override void PreInitialize()
            {
                Database.SetInitializer(new CreateDatabaseIfNotExists<PMDBContext>());
                Configuration.DefaultNameOrConnectionString = "Default";
            }
    
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
            }
        }
    }
    PMDataModule

    四、PM.Application

    1,NuGet安装Abp.Zero2.1.3、Abp.AutoMapper2.1.3

    程序集引用:System.ComponentModel.DataAnnotations

    2,基本结构

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.IdentityFramework;
    using Abp.Runtime.Session;
    using Microsoft.AspNet.Identity;
    using PM.Core;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Application
    {
        public class PMAppServiceBase:ApplicationService
        {
            public TenantManager TenantManager { get; set; }
            public UserManager UserManager { get; set; }
    
            protected PMAppServiceBase()
            {
                LocalizationSourceName = PMProjectNameConsts.LocalizationSourceName;
            }
    
            protected virtual Task<User> GetCurrentUserAsync()
            {
                var user= UserManager.FindByIdAsync(AbpSession.GetUserId());
                if (user == null)
                {
                    throw new ApplicationException("目前没有用户!");
                }
                return user;
            }
    
            protected virtual Task<Tenant> GetCurrentTenantAsync()
            {
                return TenantManager.GetByIdAsync(AbpSession.GetTenantId());
            }
    
            protected virtual void CheckErrors(IdentityResult identityResult)
            {
                identityResult.CheckErrors(LocalizationManager);
            }
    
    
        }
    }
    PMAppServiceBase
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Authorization;
    using Abp.Authorization.Roles;
    using Abp.AutoMapper;
    using Abp.Modules;
    using PM.Application.Roles.Dto;
    using PM.Application.Users.Dto;
    using PM.Core;
    using PM.Core.Authorization.Roles;
    using PM.Core.Users;
    
    namespace PM.Application
    {
        [DependsOn(typeof(PMCoreModule),typeof(AbpAutoMapperModule))]
        public class PMApplicationModule:AbpModule
        {
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
                Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
                {
                    // Role and permission
                    cfg.CreateMap<Permission, string>().ConvertUsing(r => r.Name);
                    cfg.CreateMap<RolePermissionSetting, string>().ConvertUsing(r => r.Name);
    
                    cfg.CreateMap<CreateRoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
                    cfg.CreateMap<RoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
    
                    cfg.CreateMap<UserDto, User>();
                    cfg.CreateMap<UserDto, User>().ForMember(x => x.Roles, opt => opt.Ignore());
    
                    cfg.CreateMap<CreateUserDto, User>();
                    cfg.CreateMap<CreateUserDto, User>().ForMember(x => x.Roles, opt => opt.Ignore());
                });
    
            }
        }
    }
    PMApplicationModule
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Zero.Configuration;
    using PM.Application.Authorization.Accounts.Dto;
    using PM.Core.Authorization.Users;
    using Abp.Configuration;
    namespace PM.Application.Authorization.Accounts
    {
        public class AccountAppService:PMAppServiceBase,IAccountAppService
        {
            private readonly UserRegistrationManager _userRegistrationManager;
    
            public AccountAppService(UserRegistrationManager userRegistrationManager)
            {
                _userRegistrationManager = userRegistrationManager;
            }
    
            public async Task<IsTenantAvaliableOutput> IsTenantAvaliable(IsTenantAvaliableInput input)
            {
                var tenant = await TenantManager.FindByTenancyNameAsync(input.TenantName);
                if (tenant == null)
                {
                    return new IsTenantAvaliableOutput(TenantAvaliablityState.NotFound);
                }
                if (!tenant.IsActive)
                {
                    return new IsTenantAvaliableOutput(TenantAvaliablityState.InActive);
                }
                return new IsTenantAvaliableOutput(TenantAvaliablityState.Avaliable, tenant.Id);
            }
    
            public async Task<RegisterOutput> Register(RegisterInput input)
            {
                var user =await _userRegistrationManager.RegisterAsync(input.Name, input.Surname, input.EmailAddress,
                    input.UserName,
                    input.Password, false);
    
                //电子邮件确认需要登录
                var isEmailConfirmationRequiredForLogin = await SettingManager.GetSettingValueAsync<bool>(
                    AbpZeroSettingNames.UserManagement.IsEmailConfirmationRequiredForLogin);
    
                return new RegisterOutput()
                {
                    CanLogin = user.IsActive && (user.IsEmailConfirmed || !isEmailConfirmationRequiredForLogin)
                };
            }
        }
    }
    AccountAppService
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Runtime.Session;
    using PM.Application.Configuration.Dto;
    using PM.Core.Configuration;
    
    namespace PM.Application.Configuration
    {
        public class ConfigurationAppService : PMAppServiceBase, IConfigurationAppService
        {
            public async Task ChangeUiTheme(ChangeUiThemeInput input)
            {
                await
                    SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), PMSettingNames.UiTheme,
                        input.Theme);
            }
        }
    }
    ConfigurationAppService
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.Application.Services.Dto;
    using Abp.AutoMapper;
    using Abp.Domain.Repositories;
    using Abp.Extensions;
    using Abp.IdentityFramework;
    using Abp.MultiTenancy;
    using Abp.Runtime.Security;
    using Microsoft.AspNet.Identity;
    using PM.Application.MultiTenancy.Dto;
    using PM.Core.Authorization.Roles;
    using PM.Core.Editions;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Application.MultiTenancy
    {
        public class TenantAppService :  AsyncCrudAppService<Tenant, TenantDto, int, PagedResultRequestDto, CreateTenantDto, TenantDto>, ITenantAppService
        {
            private readonly TenantManager _tenantManager;
            private readonly EditionManager _editionManager;
            private readonly UserManager _userManager;
            private readonly RoleManager _roleManager;
            private readonly IAbpZeroDbMigrator _abpZeroDbMigrator;
    
            public TenantAppService(
                IRepository<Tenant, int> repository,
                TenantManager tenantManager,
                EditionManager editionManager,
                UserManager userManager,
                RoleManager roleManager,
                IAbpZeroDbMigrator abpZeroDbMigrator
                ) : base(repository)
            {
                _editionManager = editionManager;
                _tenantManager = tenantManager;
                _userManager = userManager;
                _roleManager = roleManager;
                _abpZeroDbMigrator = abpZeroDbMigrator;
            }
    
            private void CheckError(IdentityResult identityResult)
            {
                identityResult.CheckErrors();
            }
    
            /// <summary>
            /// 创建租户
            /// </summary>
            /// <param name="input"></param>
            /// <returns></returns>
            public override async Task<TenantDto> Create(CreateTenantDto input)
            {
                //判断是否已拥有此接口的权限(Create方法),需要赋值CreatePermissionName属性
                CheckCreatePermission();
    
                var tenant = input.MapTo<Tenant>();
    
                //加密数据库链接字符串(采用AES对称加密)
                tenant.ConnectionString = input.ConnectionString.IsNullOrEmpty()
                    ? null
                    : SimpleStringCipher.Instance.Encrypt(input.ConnectionString);
    
                //当前租户使用的版本(Standard标准版)
                var defaultEdition = await _editionManager.FindByNameAsync(EditionManager.DefaultEditionName);
                if (defaultEdition != null)
                {
                    tenant.EditionId = defaultEdition.Id;
                }
    
                //创建租户
                await _tenantManager.CreateAsync(tenant);
                //获得租户的id
                await CurrentUnitOfWork.SaveChangesAsync();
    
                //创建租户数据库
                _abpZeroDbMigrator.CreateOrMigrateForTenant(tenant);
    
                using (CurrentUnitOfWork.SetTenantId(tenant.Id))
                {
                    //创建静态租户角色,该静态角色通过IRoleManagementConfig配置
                    CheckError(await _roleManager.CreateStaticRoles(tenant.Id));
                    await CurrentUnitOfWork.SaveChangesAsync();//获取静态角色id
    
                    //授予管理员角色所有权限(该权限通过IPermissionDefinitionContext配置)
                    var adminRole = _roleManager.Roles.Single(r => r.Name == StaticRoleNames.Tenants.Admin);
                    await _roleManager.GrantAllPermissionsAsync(adminRole);
    
                    //创建租户admin用户
                    var adminUser= User.CreateTenantAdminUser(tenant.Id, input.AdminEmailAddress, User.DefaultPassword);
                    CheckError(await _userManager.CreateAsync(adminUser));
                    await CurrentUnitOfWork.SaveChangesAsync();//获取用户id
    
                    //讲角色分配给租户admin用户
                    CheckError(await _userManager.AddToRoleAsync(adminUser.Id, adminRole.Name));
                    await CurrentUnitOfWork.SaveChangesAsync();
                }
    
                return MapToEntityDto(tenant);
            }
    
            protected override void MapToEntity(TenantDto updateInput, Tenant entity)
            {
                //手动映射,因为TenantDto也包含不可编辑的属性。
                entity.Name = updateInput.Name;
                entity.TenancyName = updateInput.TenancyName;
                entity.IsActive = updateInput.IsActive;
            }
    
            public override async Task Delete(EntityDto<int> input)
            {
                CheckDeletePermission();
                var tenant =await _tenantManager.FindByIdAsync(input.Id);
                await _tenantManager.DeleteAsync(tenant);
            }
        }
    }
    TenantAppService
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.Application.Services.Dto;
    using Abp.Authorization.Users;
    using Abp.AutoMapper;
    using Abp.Domain.Repositories;
    using Abp.IdentityFramework;
    using Abp.UI;
    using Microsoft.AspNet.Identity;
    using PM.Application.Roles.Dto;
    using PM.Core.Authorization.Roles;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    
    namespace PM.Application.Roles
    {
        public class RoleAppService:AsyncCrudAppService<Role,RoleDto,Int32,PagedResultRequestDto,CreateRoleDto,RoleDto>,IRoleAppService
        {
            private readonly RoleManager _roleManager;
            private readonly UserManager _userManager;
            private readonly IRepository<User, long> _userRepository;
            private readonly IRepository<UserRole, long> _userRoleRepository;
            private readonly IRepository<Role> _roleRepository; 
            public RoleAppService(
                IRepository<Role, int> repository,
                RoleManager roleManager,
                UserManager userManager,
                IRepository<User,long> userRepository,
                IRepository<UserRole,long> userRoleRepository,
                IRepository<Role> roleRepository    
                ) : base(repository)
            {
                _roleManager = roleManager;
                _userManager = userManager;
                _userRepository = userRepository;
                _userRoleRepository = userRoleRepository;
                _roleRepository = roleRepository;
            }
    
            public override async Task<RoleDto> Create(CreateRoleDto input)
            {
                CheckCreatePermission();
    
                var role = input.MapTo<Role>();
    
                CheckErrors(await _roleManager.CreateAsync(role));
    
                //查询权限
                var grantedPermissions =
                    PermissionManager.GetAllPermissions().Where(p => input.Permissions.Contains(p.Name)).ToList();
    
                //给角色设置权限
                await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
    
                return MapToEntityDto(role);
            }
    
            public override async Task Delete(EntityDto<int> input)
            {
                CheckDeletePermission();
    
                var role = await _roleManager.FindByIdAsync(input.Id);
                if (role.IsStatic)
                {
                    throw new UserFriendlyException("无法删除静态角色");
                }
    
                //删除用户角色关联
                var users = await GetUsersInRoleAsync(role.Name);
    
                foreach (var user in users)
                {
                    CheckErrors(await _userManager.RemoveFromRoleAsync(user, role.Name));
                }
    
                //删除角色
                await _roleManager.DeleteAsync(role);
            }
    
    
            private Task<List<long>> GetUsersInRoleAsync(string roleName)
            {
               var users= (from user in _userRepository.GetAll()
                    join userRole in _userRoleRepository.GetAll() on user.Id equals userRole.UserId
                    join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id
                    where role.Name == roleName
                    select user.Id).Distinct().ToList();
                return Task.FromResult(users);
            }
    
    
            public Task<ListResultDto<PermissionDto>> GetAllPermissions()
            {
                var permissions = PermissionManager.GetAllPermissions();
                return Task.FromResult(new ListResultDto<PermissionDto>(permissions.MapTo<List<PermissionDto>>()));
            }
    
            protected override Task<Role> GetEntityByIdAsync(int id)
            {
                //查询角色,并包含该角色的权限
                var role = Repository.GetAllIncluding(x => x.Permissions).FirstOrDefault(x => x.Id == id);
                return Task.FromResult(role);
            }
            /// <summary>
            /// 创建过滤查询
            /// </summary>
            /// <param name="input"></param>
            /// <returns></returns>
            protected override IQueryable<Role> CreateFilteredQuery(PagedResultRequestDto input)
            {
                return Repository.GetAllIncluding(x => x.Permissions);
            }
    
            /// <summary>
            /// 应用排序
            /// </summary>
            /// <param name="query"></param>
            /// <param name="input"></param>
            /// <returns></returns>
            protected override IQueryable<Role> ApplySorting(IQueryable<Role> query, PagedResultRequestDto input)
            {
                return query.OrderBy(r => r.DisplayName);
            }
            private void CheckErrors(IdentityResult identityResult)
            {
                identityResult.CheckErrors(LocalizationManager);
            }
        }
    }
    RoleAppService
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Auditing;
    using Abp.AutoMapper;
    using PM.Application.Sessions.Dto;
    
    namespace PM.Application.Sessions
    {
        public class SessionAppService:PMAppServiceBase,ISessionAppService
        {
    
            [DisableAuditing]
            public async Task<GetCurrentLoginInformationsOutput> GetCurrentLoginInformations()
            {
                var output=new GetCurrentLoginInformationsOutput();
                if (AbpSession.UserId.HasValue)
                {
                    output.User = (await GetCurrentUserAsync()).MapTo<UserLoginInfoDto>();
                }
                if (AbpSession.TenantId.HasValue)
                {
                    output.Tenant = (await GetCurrentTenantAsync()).MapTo<TenantLoginInfoDto>();
                }
                return output;
            }
        }
    }
    SessionAppService
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.Application.Services.Dto;
    using Abp.Authorization.Users;
    using Abp.AutoMapper;
    using Abp.Domain.Repositories;
    using Abp.IdentityFramework;
    using Microsoft.AspNet.Identity;
    using PM.Application.Roles.Dto;
    using PM.Application.Users.Dto;
    using PM.Core.Authorization.Roles;
    using PM.Core.Users;
    
    namespace PM.Application.Users
    {
        public class UserAppService:AsyncCrudAppService<User,UserDto,long,PagedResultRequestDto,CreateUserDto,UpdateUserDto>,IUserAppService
        {
            private readonly UserManager _userManager;
            private readonly IRepository<Role> _roleRepository;
            private readonly RoleManager _roleManager;
    
            public UserAppService(
                IRepository<User, long> repository,
                UserManager userManager,
                IRepository<Role> roleRepository,
                RoleManager roleManager 
                ) : base(repository)
            {
                _userManager = userManager;
                _roleRepository = roleRepository;
                _roleManager = roleManager;
            }
    
            public override async Task<UserDto> Get(EntityDto<long> input)
            {
                var user = await base.Get(input);
                var userRoles = await _userManager.GetRolesAsync(user.Id);
                user.Roles = userRoles.ToArray();
                return user;
            }
    
            public override async Task<UserDto> Create(CreateUserDto input)
            {
                CheckCreatePermission();
                var user = input.MapTo<User>();
                user.TenantId = AbpSession.TenantId;
                user.Password = new PasswordHasher().HashPassword(input.Password);
                user.IsEmailConfirmed = true;
    
                //分配角色(从租户的所有)
                user.Roles = new Collection<UserRole>();
                foreach (var roleName in input.RoleNames)
                {
                    var role = await _roleManager.GetRoleByNameAsync(roleName);
                    user.Roles.Add(new UserRole(AbpSession.TenantId, user.Id, role.Id));
                }
                CheckErrors(await _userManager.CreateAsync(user));
                return MapToEntityDto(user);
            }
    
            public override async Task<UserDto> Update(UpdateUserDto input)
            {
                CheckUpdatePermission();
                var user = await _userManager.GetUserByIdAsync(input.Id);
    
                //把有变动的属性赋值到user对象中
                MapToEntity(input, user);
    
                CheckErrors(await _userManager.UpdateAsync(user));
    
                if (input.RoleNames != null)
                {
                    //_userManager.SetRoles方法的作用:变更角色(前提:用户表以已经创建)
                    CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
                }
    
                return await Get(input);
            }
    
            public override async Task Delete(EntityDto<long> input)
            {
                var user = await _userManager.GetUserByIdAsync(input.Id);
    
                //admin用户不能被删除(删除用户的同时会删除UserRole)
                await _userManager.DeleteAsync(user);
            }
            public async Task<ListResultDto<RoleDto>> GetRoles()
            {
                var roles = await _roleRepository.GetAllListAsync();
                return new ListResultDto<RoleDto>(roles.MapTo<List<RoleDto>>());
            }
    
            protected override User MapToEntity(CreateUserDto createInput)
            {
                var user = ObjectMapper.Map<User>(createInput);
                return user;
            }
    
            protected override void MapToEntity(UpdateUserDto updateInput, User entity)
            {
                ObjectMapper.Map(updateInput, entity);
            }
    
            protected override IQueryable<User> CreateFilteredQuery(PagedResultRequestDto input)
            {
                return Repository.GetAllIncluding(x => x.Roles);
            }
    
            protected override async Task<User> GetEntityByIdAsync(long id)
            {
                var user = Repository.GetAllIncluding(x => x.Roles).FirstOrDefault(x => x.Id == id);
                return await Task.FromResult(user);
            }
            protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedResultRequestDto input)
            {
                return query.OrderBy(r => r.UserName);
            }
    
            private void CheckErrors(IdentityResult identityResult)
            {
                identityResult.CheckErrors(LocalizationManager);
            }
        }
    }
    UserAppService

    五、PM.WebApi

    1,NuGet安装:

    Abp.Zero、Abp.Web.Api、Abp.AutoMapper、Microsoft.Owin.Security.OAuth、Microsoft.AspNet.WebApi.Owin

    System.ComponentModel.DataAnnotations

    2,WebApiModule

    using System.Web.Http;
    using Abp.Application.Services;
    using Abp.Configuration.Startup;
    using Abp.Modules;
    using Abp.WebApi;
    
    namespace MyPassword.Api
    {
        [DependsOn(typeof(AbpWebApiModule), typeof(MyPasswordApplicationModule))]
        public class MyPasswordWebApiModule : AbpModule
        {
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    
                Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder
                    .ForAll<IApplicationService>(typeof(MyPasswordApplicationModule).Assembly, "app")
                    .Build();
    
                //添加访问令牌类型(Access Token Types)过滤(不加这句话也支持Bearer)
                Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new HostAuthenticationFilter("Bearer"));
            }
        }
    }

    备注:访问令牌类型(Access Token Types)包括bearer类型或mac类型。

    ①bearer类型

    [RFC6750]中定义的“bearer”令牌类型被简单地包含在请求中的访问令牌字符串中:

         GET /resource/1 HTTP/1.1
         Host: example.com
         Authorization: Bearer mF_9.B5f-4.1JqM

    ②mac类型

    而[OAuth-HTTP-MAC]中定义的“mac”令牌类型是通过发送消息认证码(MAC)密钥与用于签署HTTP请求的某些组件的访问令牌一起使用的:

         GET /resource/1 HTTP/1.1
         Host: example.com
         Authorization: MAC id="h480djs93hd8",
                            nonce="274312:dj83hs9s",
                            mac="kDZvddkndxvhGRXZhvuDjEWhGeE="

    3,AccountController(获取访问令牌)

    using System;
    using System.Threading.Tasks;
    using System.Web.Http;
    using Abp.Authorization;
    using Abp.Authorization.Users;
    using Abp.UI;
    using Abp.Web.Models;
    using Abp.WebApi.Controllers;
    using MyPassword.Api.Models;
    using MyPassword.Authorization;
    using MyPassword.Authorization.Users;
    using MyPassword.MultiTenancy;
    using MyPassword.Users;
    using Microsoft.Owin.Infrastructure;
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.OAuth;
    
    namespace MyPassword.Api.Controllers
    {
        public class AccountController : AbpApiController
        {
            public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
    
            private readonly LogInManager _logInManager;
    
            static AccountController()
            {
                OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
            }
    
            public AccountController(LogInManager logInManager)
            {
                _logInManager = logInManager;
                LocalizationSourceName = MyPasswordConsts.LocalizationSourceName;
            }
    
            //获取访问令牌
            [HttpPost]
            public async Task<AjaxResponse> Authenticate(LoginModel loginModel)
            {
                CheckModelState();
    
                var loginResult = await GetLoginResultAsync(
                    loginModel.UsernameOrEmailAddress,
                    loginModel.Password,
                    loginModel.TenancyName
                    );
    
                var ticket = new AuthenticationTicket(loginResult.Identity, new AuthenticationProperties());
    
                var currentUtc = new SystemClock().UtcNow;
                ticket.Properties.IssuedUtc = currentUtc;
                ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
    
                return new AjaxResponse(OAuthBearerOptions.AccessTokenFormat.Protect(ticket));
            }
    
            private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
            {
                var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
    
                switch (loginResult.Result)
                {
                    case AbpLoginResultType.Success:
                        return loginResult;
                    default:
                        throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
                }
            }
    
            private Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName)
            {
                switch (result)
                {
                    case AbpLoginResultType.Success:
                        return new ApplicationException("Don't call this method with a success result!");
                    case AbpLoginResultType.InvalidUserNameOrEmailAddress:
                    case AbpLoginResultType.InvalidPassword:
                        return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));
                    case AbpLoginResultType.InvalidTenancyName:
                        return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
                    case AbpLoginResultType.TenantIsNotActive:
                        return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));
                    case AbpLoginResultType.UserIsNotActive:
                        return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
                    case AbpLoginResultType.UserEmailIsNotConfirmed:
                        return new UserFriendlyException(L("LoginFailed"), "Your email address is not confirmed. You can not login"); //TODO: localize message
                    default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
                        Logger.Warn("Unhandled login fail reason: " + result);
                        return new UserFriendlyException(L("LoginFailed"));
                }
            }
    
            protected virtual void CheckModelState()
            {
                if (!ModelState.IsValid)
                {
                    throw new UserFriendlyException("Invalid request!");
                }
            }
        }
    }
    AccountController

    4,Web工程下的Startup.cs

    app.UseOAuthBearerAuthentication(AccountController.OAuthBearerOptions);

    将Bearer Token处理添加到OWIN应用程序管道。
    这个中间件理解适当的格式化和安全的令牌出现在请求头。
    如果Options.AuthenticationMode处于Active状态,则不记名令牌(bearer token)中的声明将被添加到当前请求的IPrincipal用户。
    如果Options.AuthenticationMode是Passive的,那么当前请求不被修改,但IAuthenticationManager AuthenticateAsync可以随时用来从请求的不记名令牌(bearer token)中获得请求。
    另见http://tools.ietf.org/html/rfc6749

    5,案例

    请求授权接口

    返回令牌

    请求受保护的资源

    六、PM.Web(MPA)

    1,NuGet安装:Abp.Zero、Abp.EntityFramework、Abp.Zero.EntityFramework、Abp.Web.Api、Abp.Web.Mvc、Abp.AutoMapper、Abp.Castle.Log4Net、Abp.Owin

    可选则安装:Abp.Web.SignalR

    注意,先安装Abp.EntityFramework再安装Abp.Zero.EntityFramework

    针对通用的依赖类型的解析与创建,微软默认定义了4种类别的生命周期,分别如下:

    类型描述
    Instance 任何时间都只能使用特定的实例对象,开发人员需要负责该对象的初始化工作。
    Transient 每次都重新创建一个实例。
    Singleton 创建一个单例,以后每次调用的时候都返回该单例对象。
    Scoped 在当前作用域内,不管调用多少次,都是一个实例,换了作用域就会再次创建实例,类似于特定作用内的单例。

    前端笔记

    1,按钮

    <button type="button" class="btn btn-primary btn-circle waves-effect waves-circle waves-float"  data-toggle="modal"><i class="material-icons">add</i></button>

    btn-circle:圆形按钮

    pull-right:右浮动

    waves-effect:点击按钮波浪效果

    waves-block:块状效果

    waves-circle:圆状效果

    waves-float:效果浮动

    2, 模态框

    <a href="#" class="waves-effect waves-block edit-role" data-role-id="@role.Id" data-toggle="modal" data-target="#RoleEditModal"><i class="material-icons">edit</i>@L("Edit")</a>
    <div class="modal fade" id="RoleEditModal" tabindex="-1" role="dialog" aria-labelledby="RoleEditModalLabel" data-backdrop="static">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
    
            </div>
        </div>
    </div>
    <div class="modal fade" id="RoleCreateModal" tabindex="-1" role="dialog" aria-labelledby="RoleCreateModalLabel" data-backdrop="static">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">
                        <span>@L("CreateNewRole")</span>
                    </h4>
                </div>
                <div class="modal-body">
                    <form name="roleCreateForm" role="form" novalidate class="form-validation">
                        <div class="row clearfix">
                            <div class="col-sm-12">
                                <div class="form-group form-float">
                                    <div class="form-line">
                                        <input id="rolename" type="text" name="Name" required maxlength="32" minlength="2" class="validate form-control">
                                        <label for="rolename" class="form-label">@L("RoleName")</label>
                                    </div>
                                </div>
                            </div>
                        </div>
    
                        <div class="row clearfix">
                            <div class="col-sm-12">
                                <div class="form-group form-float">
                                    <div class="form-line">
                                        <input id="displayname" type="text" name="DisplayName" required maxlength="32" minlength="2" class="validate form-control">
                                        <label for="displayname" class="form-label">@L("DisplayName")</label>
                                    </div>
                                </div>
                            </div>
                        </div>
    
                        <div class="row">
                            <div class="col-sm-12">
                                <div class="form-group form-float">
                                    <div class="form-line">
                                        <textarea id="role-description" name="Description" class="validate form-control"></textarea>
                                        <label for="role-description" class="form-label">Role Description</label>
                                    </div>
                                </div>
                            </div>
                        </div>
    
                        <div class="row clearfix">
                            <div class="col-sm-12">
                                <h4>Permissions</h4>
                                @foreach (var permission in Model.Permissions)
                                {
                                    <div class="col-sm-6">
                                        <input type="checkbox" name="permission" value="@permission.Name" class="filled-in" id="@string.Format("permission{0}",permission.Name)" checked="checked" />
                                        <label for="@string.Format("permission{0}",permission.Name)">@permission.DisplayName</label>
                                    </div>
                                }
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default waves-effect" data-dismiss="modal">@L("Cancel")</button>
                            <button type="submit" class="btn btn-primary waves-effect">@L("Save")</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    View Code

    3,for属性

    在用户注册的时候,常常用户点击文字就需要将光标聚焦到对应的表单上面,这个是怎么实现的呢?就是下面我要介绍的<label>标签的for属性

    定义:for 属性规定 label 与哪个表单元素绑定

                      <div class="form-line">
                                        <input id="rolename" type="text" name="Name" required maxlength="32" minlength="2" class="validate form-control">
                                        <label for="rolename" class="form-label">@L("RoleName")</label>
                                    </div>

    七、PM.Web(SPA)

    八、单元测试

    1,NuGet安装:

    Abp.TestBase、Abp.EntityFramework、Effort.EF6、xunit、Shouldly、xunit.runner.visualstudio、Abp.Zero.EntityFramework、NSubstitute

    2,基本结构

    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp;
    using Abp.Configuration.Startup;
    using Abp.Domain.Uow;
    using Abp.Runtime.Session;
    using Abp.TestBase;
    using Castle.MicroKernel.Registration;
    using Effort;
    using EntityFramework.DynamicFilters;
    using PM.Core.MultiTenant;
    using PM.Core.Users;
    using PM.EntityFramework.EntityFramework;
    using PM.EntityFramework.Migrations.SeedData;
    
    namespace PM.Test
    {
        public class PMTestBase: AbpIntegratedTestBase<PMTestModule>
        {
            private DbConnection _hostDb;
            private Dictionary<int, DbConnection> _tenantDbs; //only used for db per tenant architecture
    
            protected PMTestBase()
            {
                //Seed initial data for host
                AbpSession.TenantId = null;
                UsingDbContext(context =>
                {
                    new InitialHostDbBuilder(context).Create();
                    new DefaultTenantCreator(context).Create();
                });
    
                //Seed initial data for default tenant
                AbpSession.TenantId = 1;
                UsingDbContext(context =>
                {
                    new TenantRoleAndUserBuilder(context, 1).Create();
                });
    
                LoginAsDefaultTenantAdmin();
            }
    
            protected override void PreInitialize()
            {
                base.PreInitialize();
    
                /* You can switch database architecture here: */
                UseSingleDatabase();
                //UseDatabasePerTenant();
            }
    
            /* Uses single database for host and all tenants.
             */
            private void UseSingleDatabase()
            {
                _hostDb = DbConnectionFactory.CreateTransient();
    
                LocalIocManager.IocContainer.Register(
                    Component.For<DbConnection>()
                        .UsingFactoryMethod(() => _hostDb)
                        .LifestyleSingleton()
                    );
            }
    
            /* Uses single database for host and Default tenant,
             * but dedicated databases for all other tenants.
             */
            private void UseDatabasePerTenant()
            {
                _hostDb = DbConnectionFactory.CreateTransient();
                _tenantDbs = new Dictionary<int, DbConnection>();
    
                LocalIocManager.IocContainer.Register(
                    Component.For<DbConnection>()
                        .UsingFactoryMethod((kernel) =>
                        {
                            lock (_tenantDbs)
                            {
                                var currentUow = kernel.Resolve<ICurrentUnitOfWorkProvider>().Current;
                                var abpSession = kernel.Resolve<IAbpSession>();
    
                                var tenantId = currentUow != null ? currentUow.GetTenantId() : abpSession.TenantId;
    
                                if (tenantId == null || tenantId == 1) //host and default tenant are stored in host db
                                {
                                    return _hostDb;
                                }
    
                                if (!_tenantDbs.ContainsKey(tenantId.Value))
                                {
                                    _tenantDbs[tenantId.Value] = DbConnectionFactory.CreateTransient();
                                }
    
                                return _tenantDbs[tenantId.Value];
                            }
                        }, true)
                        .LifestyleTransient()
                    );
            }
    
            #region UsingDbContext
    
            protected IDisposable UsingTenantId(int? tenantId)
            {
                var previousTenantId = AbpSession.TenantId;
                AbpSession.TenantId = tenantId;
                return new DisposeAction(() => AbpSession.TenantId = previousTenantId);
            }
    
            protected void UsingDbContext(Action<PMDBContext> action)
            {
                UsingDbContext(AbpSession.TenantId, action);
            }
    
            protected Task UsingDbContextAsync(Func<PMDBContext, Task> action)
            {
                return UsingDbContextAsync(AbpSession.TenantId, action);
            }
    
            protected T UsingDbContext<T>(Func<PMDBContext, T> func)
            {
                return UsingDbContext(AbpSession.TenantId, func);
            }
    
            protected Task<T> UsingDbContextAsync<T>(Func<PMDBContext, Task<T>> func)
            {
                return UsingDbContextAsync(AbpSession.TenantId, func);
            }
    
            protected void UsingDbContext(int? tenantId, Action<PMDBContext> action)
            {
                using (UsingTenantId(tenantId))
                {
                    using (var context = LocalIocManager.Resolve<PMDBContext>())
                    {
                        context.DisableAllFilters();
                        action(context);
                        context.SaveChanges();
                    }
                }
            }
    
            protected async Task UsingDbContextAsync(int? tenantId, Func<PMDBContext, Task> action)
            {
                using (UsingTenantId(tenantId))
                {
                    using (var context = LocalIocManager.Resolve<PMDBContext>())
                    {
                        context.DisableAllFilters();
                        await action(context);
                        await context.SaveChangesAsync();
                    }
                }
            }
    
            protected T UsingDbContext<T>(int? tenantId, Func<PMDBContext, T> func)
            {
                T result;
    
                using (UsingTenantId(tenantId))
                {
                    using (var context = LocalIocManager.Resolve<PMDBContext>())
                    {
                        context.DisableAllFilters();
                        result = func(context);
                        context.SaveChanges();
                    }
                }
    
                return result;
            }
    
            protected async Task<T> UsingDbContextAsync<T>(int? tenantId, Func<PMDBContext, Task<T>> func)
            {
                T result;
    
                using (UsingTenantId(tenantId))
                {
                    using (var context = LocalIocManager.Resolve<PMDBContext>())
                    {
                        context.DisableAllFilters();
                        result = await func(context);
                        await context.SaveChangesAsync();
                    }
                }
    
                return result;
            }
    
            #endregion
    
            #region Login
    
            protected void LoginAsHostAdmin()
            {
                LoginAsHost(User.AdminUserName);
            }
    
            protected void LoginAsDefaultTenantAdmin()
            {
                LoginAsTenant(Tenant.DefaultTenantName, User.AdminUserName);
            }
    
            protected void LogoutAsDefaultTenant()
            {
                LogoutAsTenant(Tenant.DefaultTenantName);
            }
    
            protected void LoginAsHost(string userName)
            {
                AbpSession.TenantId = null;
    
                var user =
                    UsingDbContext(
                        context =>
                            context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName));
                if (user == null)
                {
                    throw new Exception("There is no user: " + userName + " for host.");
                }
    
                AbpSession.UserId = user.Id;
            }
    
            protected void LogoutAsHost()
            {
                Resolve<IMultiTenancyConfig>().IsEnabled = true;
    
                AbpSession.TenantId = null;
                AbpSession.UserId = null;
            }
    
            protected void LoginAsTenant(string tenancyName, string userName)
            {
                var tenant = UsingDbContext(context => context.Tenants.FirstOrDefault(t => t.TenancyName == tenancyName));
                if (tenant == null)
                {
                    throw new Exception("There is no tenant: " + tenancyName);
                }
    
                AbpSession.TenantId = tenant.Id;
    
                var user =
                    UsingDbContext(
                        context =>
                            context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName));
                if (user == null)
                {
                    throw new Exception("There is no user: " + userName + " for tenant: " + tenancyName);
                }
    
                AbpSession.UserId = user.Id;
            }
    
            protected void LogoutAsTenant(string tenancyName)
            {
                var tenant = UsingDbContext(context => context.Tenants.FirstOrDefault(t => t.TenancyName == tenancyName));
                if (tenant == null)
                {
                    throw new Exception("There is no tenant: " + tenancyName);
                }
    
                AbpSession.TenantId = tenant.Id;
                AbpSession.UserId = null;
            }
    
            #endregion
    
            /// <summary>
            /// Gets current user if <see cref="IAbpSession.UserId"/> is not null.
            /// Throws exception if it's null.
            /// </summary>
            protected async Task<Core.Users.User> GetCurrentUserAsync()
            {
                var userId = AbpSession.GetUserId();
                return await UsingDbContext(context => context.Users.SingleAsync(u => u.Id == userId));
            }
    
            /// <summary>
            /// Gets current tenant if <see cref="IAbpSession.TenantId"/> is not null.
            /// Throws exception if there is no current tenant.
            /// </summary>
            protected async Task<Tenant> GetCurrentTenantAsync()
            {
                var tenantId = AbpSession.GetTenantId();
                return await UsingDbContext(context => context.Tenants.SingleAsync(t => t.Id == tenantId));
            }
        }
    }
    PMTestBase
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Abp.Modules;
    using Abp.MultiTenancy;
    using Abp.TestBase;
    using Abp.Zero.Configuration;
    using Castle.MicroKernel.Registration;
    using NSubstitute;
    using PM.Application;
    using PM.EntityFramework;
    
    namespace PM.Test
    {
        [DependsOn(
               typeof(PMDataModule),
               typeof(PMApplicationModule),
               typeof(AbpTestBaseModule)
           )]
        public class PMTestModule:AbpModule
        {
            public override void PreInitialize()
            {
                //使用数据库进行语言管理
                Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();
    
                //注册伪服务
    
                IocManager.IocContainer.Register(
                    Component.For<IAbpZeroDbMigrator>()
                        .UsingFactoryMethod(() => Substitute.For<IAbpZeroDbMigrator>())
                        .LifestyleSingleton()
                    );
            }
        }
    }
    PMTestModule
    using Xunit;
    
    namespace AbpCompanyName.AbpProjectName.Tests
    {
        public sealed class MultiTenantFactAttribute : FactAttribute
        {
            public MultiTenantFactAttribute()
            {
                if (!AbpProjectNameConsts.MultiTenancyEnabled)
                {
                    Skip = "MultiTenancy is disabled.";
                }
            }
        }
    }
    MultiTenantFactAttribute
  • 相关阅读:
    Thymeleaf+Spring使用自己的工具类
    bootstrap 响应式布局
    bootstrap 流布局
    bootstrap 布局
    bootstrap 新建网页
    quick 定时更新函数
    acm hdoj 1157
    acm hdoj 今年暑假不ac
    quick removeTileMaptile
    quick schedule 的添加和移除
  • 原文地址:https://www.cnblogs.com/zd1994/p/7727606.html
Copyright © 2020-2023  润新知