一、基础层搭建

二、PM.Core

三、PM.EntityFramework

四、PM.Application

五、PM.WebApi 

六、PM.Web(MPA)

七、PM.Web(SPA)

八、单元测试

一、基础层搭建

1,创建一个空解决方案 

2,层结构

ACEM2引擎源码_ViewUI

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,基本结构

ACEM2引擎源码_ViewUI_02

Authorization

ACEM2引擎源码_ACEM2引擎源码_03




ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_ACEM2引擎源码_28




ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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



ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_数据库_33




ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_ViewUI_36

 

ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_前端_39


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

<?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

ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

<?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

ACEM2引擎源码_前端_44


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

ACEM2引擎源码_ViewUI_49


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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 公共常量类


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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 版本帮助类


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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模块类


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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,基本结构

ACEM2引擎源码_ACEM2引擎源码_58

 

ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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,基本结构

ACEM2引擎源码_ACEM2引擎源码_85

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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(获取访问令牌)


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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,案例

请求授权接口

ACEM2引擎源码_ACEM2引擎源码_104

返回令牌

ACEM2引擎源码_ViewUI_105

 

请求受保护的资源

ACEM2引擎源码_ACEM2引擎源码_106

 

 

 

六、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>


ACEM2引擎源码_ViewUI_107

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>


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

<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,基本结构


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

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

 


ACEM2引擎源码_runtime_04

ACEM2引擎源码_ACEM2引擎源码_05

using Xunit;

namespace AbpCompanyName.AbpProjectName.Tests
{
    public sealed class MultiTenantFactAttribute : FactAttribute
    {
        public MultiTenantFactAttribute()
        {
            if (!AbpProjectNameConsts.MultiTenancyEnabled)
            {
                Skip = "MultiTenancy is disabled.";
            }
        }
    }
}

MultiTenantFactAttribute