一、基础层搭建
二、PM.Core
三、PM.EntityFramework
四、PM.Application
五、PM.WebApi
六、PM.Web(MPA)
七、PM.Web(SPA)
八、单元测试
一、基础层搭建
1,创建一个空解决方案
2,层结构
PM.Core[v:4.6]:类库
PM.EntityFramework[v:4.6]:类库(引用PM.Core)
PM.Application[v:4.6]:类库(引用PM.Core)
PM.WebApi[v:4.6]:类库(引用PM.Application、PM.Core)
PM.Web[v:4.6]:WebMvc5.X(引用PM.Core、PM.EntityFramework、PM.Application、PM.WebApi)
PM.Test[v:4.6]:(引用PM.EntityFramework、PM.Core、PM.Application)
二、PM.Core
1,NuGet安装Abp.Zero2.1.3
程序集引用:System.ComponentModel.DataAnnotations
2,基本结构
Authorization
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.MultiTenancy;
using Abp.Zero.Configuration;
namespace PM.Core.Authorization.Roles
{
public class PMRoleConfig
{
public static void Configure(IRoleManagementConfig roleManagementConfig)
{
//静态主机角色
roleManagementConfig.StaticRoles.Add(new StaticRoleDefinition(
StaticRoleNames.Host.Admin
, MultiTenancySides.Host));
//静态租户角色
roleManagementConfig.StaticRoles.Add(new StaticRoleDefinition(
StaticRoleNames.Tenants.Admin,
MultiTenancySides.Tenant));
}
}
}
PMRoleConfig
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization.Roles;
using PM.Core.Users;
namespace PM.Core.Authorization.Roles
{
public class Role : AbpRole<User>
{
}
}
Role
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Domain.Uow;
using Abp.Runtime.Caching;
using Abp.Zero.Configuration;
using PM.Core.Users;
namespace PM.Core.Authorization.Roles
{
public class RoleManager:AbpRoleManager<Role,User>
{
public RoleManager(
RoleStore store,
IPermissionManager permissionManager,
IRoleManagementConfig roleManagementConfig,
ICacheManager cacheManager,
IUnitOfWorkManager unitOfWorkManager)
: base(store,
permissionManager,
roleManagementConfig,
cacheManager,
unitOfWorkManager)
{
}
}
}
RoleManager
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.Domain.Repositories;
using PM.Core.Users;
namespace PM.Core.Authorization.Roles
{
public class RoleStore:AbpRoleStore<Role,User>
{
public RoleStore(
IRepository<Role> roleRepository,
IRepository<UserRole, long> userRoleRepository,
IRepository<RolePermissionSetting, long> rolePermissionSettingRepository)
: base(roleRepository,
userRoleRepository,
rolePermissionSettingRepository)
{
}
}
}
RoleStore
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PM.Core.Authorization.Roles
{
public class StaticRoleNames
{
public static class Host
{
public const string Admin = "Admin";
}
public static class Tenants
{
public const string Admin = "Admin";
}
}
}
StaticRoleNames
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.IdentityFramework;
using Abp.Localization;
using Abp.Organizations;
using Abp.Runtime.Caching;
using PM.Core.Authorization.Roles;
namespace PM.Core.Users
{
public class UserManager : AbpUserManager<Role, User>
{
public UserManager(
UserStore userStore,
RoleManager roleManager,
IPermissionManager permissionManager,
IUnitOfWorkManager unitOfWorkManager,
ICacheManager cacheManager,
IRepository<OrganizationUnit, long> organizationUnitRepository,
IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
IOrganizationUnitSettings organizationUnitSettings,
ILocalizationManager localizationManager,
IdentityEmailMessageService emailService,
ISettingManager settingManager,
IUserTokenProviderAccessor userTokenProviderAccessor)
: base(
userStore,
roleManager,
permissionManager,
unitOfWorkManager,
cacheManager,
organizationUnitRepository,
userOrganizationUnitRepository,
organizationUnitSettings,
localizationManager,
emailService,
settingManager,
userTokenProviderAccessor)
{
}
}
}
UserManager
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization.Users;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using PM.Core.Authorization.Roles;
namespace PM.Core.Users
{
public class UserStore:AbpUserStore<Role,User>
{
public UserStore(
IRepository<User, long> userRepository,
IRepository<UserLogin, long> userLoginRepository,
IRepository<UserRole, long> userRoleRepository,
IRepository<Role> roleRepository,
IRepository<UserPermissionSetting, long> userPermissionSettingRepository,
IUnitOfWorkManager unitOfWorkManager,
IRepository<UserClaim, long> userClaimRepository)
: base(
userRepository,
userLoginRepository,
userRoleRepository,
roleRepository,
userPermissionSettingRepository,
unitOfWorkManager,
userClaimRepository)
{
}
}
}
UserStore
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Configuration.Startup;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Zero.Configuration;
using PM.Core.Authorization.Roles;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Core.Authorization
{
public class LogInManager : AbpLogInManager<Tenant,Role,User>
{
public LogInManager(
UserManager userManager,
IMultiTenancyConfig multiTenancyConfig,
IRepository<Tenant> tenantRepository,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IRepository<UserLoginAttempt, long> userLoginAttemptRepository,
IUserManagementConfig userManagementConfig,
IIocResolver iocResolver,
RoleManager roleManager)
: base(
userManager,
multiTenancyConfig,
tenantRepository,
unitOfWorkManager,
settingManager,
userLoginAttemptRepository,
userManagementConfig,
iocResolver,
roleManager)
{
}
}
}
LogInManager
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Users;
using PM.Core.Authorization.Roles;
using PM.Core.Users;
namespace PM.Core.Authorization
{
public class PermissionChecker:PermissionChecker<Role,User>
{
public PermissionChecker(UserManager userManager) : base(userManager)
{
}
}
}
PermissionChecker
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PM.Core.Authorization
{
public class PermisstionNames
{
public const string Pages_Tenants = "Pages.Tenants";
public const string Pages_Users = "Pages.Users";
public const string Pages_Roles = "Pages.Roles";
}
}
PermisstionNames
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Localization;
using Abp.Localization.Sources;
using Abp.MultiTenancy;
namespace PM.Core.Authorization
{
public class PMProjectNameAuthorizationProvider: AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermisstionNames.Pages_Users, L("Users"));
context.CreatePermission(PermisstionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermisstionNames.Pages_Tenants, L("Tenants"),multiTenancySides:MultiTenancySides.Host);
}
private static ILocalizableString L(string name)
{
return new LocalizableString(name, PMProjectNameConsts.LocalizationSourceName);
}
}
}
PMProjectNameAuthorizationProvider
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization.Users;
using Abp.Extensions;
using Microsoft.AspNet.Identity;
namespace PM.Core.Users
{
public class User:AbpUser<User>
{
public const string DefaultPassword = "123qwe";
/// <summary>
/// 创建随机密码
/// </summary>
/// <returns></returns>
public static string CreateRandomPassword()
{
//截断16位
return Guid.NewGuid().ToString("N").Truncate(16);
}
public static User CreateTenantAdminUser(int tenantId, string emailAddress, string password)
{
return new User()
{
TenantId = tenantId,
UserName = AdminUserName,
Name = AdminUserName,
Surname = AdminUserName,
EmailAddress = emailAddress,
Password = new PasswordHasher().HashPassword(password),
IsEmailConfirmed = true,
IsActive = true
};
}
}
}
User
Configuration
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PM.Core.Configuration
{
public class PMSettingNames
{
public const string UiTheme = "App.UiTheme";
}
}
PMSettingNames
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Configuration;
namespace PM.Core.Configuration
{
public class PMSettingProvider:SettingProvider
{
public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
{
return new[]
{
new SettingDefinition(PMSettingNames.UiTheme, "red",
scopes: SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User,
isVisibleToClients: true)
};
}
}
}
PMSettingProvider
Editions
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Editions;
using Abp.Application.Features;
using Abp.Domain.Repositories;
namespace PM.Core.Editions
{
public class EditionManager:AbpEditionManager
{
public const string DefaultEditionName = "Standard";
public EditionManager(
IRepository<Edition> editionRepository,
IAbpZeroFeatureValueStore featureValueStore)
: base(editionRepository,
featureValueStore)
{
}
}
}
EditionManager
Features
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Features;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.MultiTenancy;
using Abp.Runtime.Caching;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Core.Features
{
public class FeaturesValueStore:AbpFeatureValueStore<Tenant,User>
{
public FeaturesValueStore(
ICacheManager cacheManager,
IRepository<TenantFeatureSetting, long> tenantFeatureRepository,
IRepository<Tenant> tenantRepository,
IRepository<EditionFeatureSetting, long> editionFeatureRepository,
IFeatureManager featureManager,
IUnitOfWorkManager unitOfWorkManager)
: base(
cacheManager,
tenantFeatureRepository,
tenantRepository,
editionFeatureRepository,
featureManager,
unitOfWorkManager)
{
}
}
}
FeaturesValueStore
Localization
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="zh-CN">
<texts>
<text name="Users" value="用户"/>
<text name="Roles" value="角色"/>
<text name="Tenants" value="租户"/>
</texts>
</localizationDictionary>
PMProjectName-zh-CN.xml
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="en">
<texts>
<text name="Users" value="Users"/>
<text name="Roles" value="Roles"/>
<text name="Tenants" value="Tenants"/>
</texts>
</localizationDictionary>
PMProjectName.xml
MultiTenant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.MultiTenancy;
using PM.Core.Users;
namespace PM.Core.MultiTenant
{
public class Tenant:AbpTenant<User>
{
}
}
Tenant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Editions;
using Abp.Application.Features;
using Abp.Domain.Repositories;
using Abp.MultiTenancy;
using PM.Core.Users;
namespace PM.Core.MultiTenant
{
public class TenantManager:AbpTenantManager<Tenant,User>
{
public TenantManager(
IRepository<Tenant> tenantRepository,
IRepository<TenantFeatureSetting, long> tenantFeatureRepository,
AbpEditionManager editionManager,
IAbpZeroFeatureValueStore featureValueStore)
: base(tenantRepository,
tenantFeatureRepository,
editionManager,
featureValueStore)
{
}
}
}
TenantManager
Validation
using Abp.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace PM.Core.Validation
{
public class ValidationHelper
{
public const string EmailRegex = @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
public static bool IsEmail(string value)
{
if (value.IsNullOrEmpty())
{
return false;
}
var regex = new Regex(EmailRegex);
return regex.IsMatch(value);
}
}
}
ValidationHelper
PMProjectNameConsts 公共常量类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PM.Core
{
public class PMProjectNameConsts
{
public const string LocalizationSourceName = "PMProjectName";
public const bool MultiTenantEnabled = true;
}
}
PMProjectNameConsts
PMVersionHepler 版本帮助类
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Reflection.Extensions;
namespace PM.Core
{
/// <summary>
/// 应用版本中心
/// </summary>
public class PMVersionHepler
{
/// <summary>
/// 获取应用程序当前版本
/// 显示在网页中
/// </summary>
public const string Version = "1.0.0.0";
/// <summary>
/// 获取应用程序最后一次发布的时间
/// 它显示在网页中
/// </summary>
public static DateTime ReleaseDate
{
get { return new FileInfo(typeof(PMVersionHepler).GetAssembly().Location).LastWriteTime; }
}
}
}
PMVersionHepler
PMCoreModule模块类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Abp.Localization.Dictionaries;
using Abp.Localization.Dictionaries.Xml;
using Abp.Modules;
using Abp.Zero;
using Abp.Zero.Configuration;
using PM.Core.Authorization;
using PM.Core.Authorization.Roles;
using PM.Core.Configuration;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Core
{
[DependsOn(typeof(AbpZeroCoreModule))]
public class PMCoreModule:AbpModule
{
public override void PreInitialize()
{
//如果当前用户未登录,请设置为true以启用保存审核日志。默认值:
Configuration.Auditing.IsEnabledForAnonymousUsers = true;
//声明实体类型
Configuration.Modules.Zero().EntityTypes.Tenant = typeof (Tenant);
Configuration.Modules.Zero().EntityTypes.Role = typeof (Role);
Configuration.Modules.Zero().EntityTypes.User = typeof (User);
//开启多租户
Configuration.MultiTenancy.IsEnabled = PMProjectNameConsts.MultiTenantEnabled;
//添加删除本地化源
Configuration.Localization.Sources.Add(
new DictionaryBasedLocalizationSource(PMProjectNameConsts.LocalizationSourceName,
new XmlEmbeddedFileLocalizationDictionaryProvider(Assembly.GetExecutingAssembly(),
"PM.Localization.Source")));
//设置静态角色
PMRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
//初始化权限
Configuration.Authorization.Providers.Add<PMProjectNameAuthorizationProvider>();
//初始化设置
Configuration.Settings.Providers.Add<PMSettingProvider>();
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
}
PMCoreModule
三、PM.EntityFramework
1,NuGet安装Abp.Zero2.1.3、Abp.Zero.EntityFramework2.13
2,基本结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Entities;
using Abp.EntityFramework;
using Abp.EntityFramework.Repositories;
namespace PM.EntityFramework.EntityFramework.Repositories
{
public class PMRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<PMDBContext, TEntity, TPrimaryKey>
where TEntity:class,IEntity<TPrimaryKey>
{
public PMRepositoryBase(IDbContextProvider<PMDBContext> dbContextProvider) : base(dbContextProvider)
{
}
//为所有存储库添加常用方法
}
public class PMRepositoryBase<TEntity> : PMRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
public PMRepositoryBase(IDbContextProvider<PMDBContext> dbContextProvider) : base(dbContextProvider)
{
}
//不要在这里添加任何方法,添加到上面的类(因为它继承它)
}
}
PMRepositoryBase
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Zero.EntityFramework;
using PM.Core.Authorization.Roles;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.EntityFramework.EntityFramework
{
public class PMDBContext:AbpZeroDbContext<Tenant,Role,User>
{
/// <summary>
/// 将“默认”设置为基类可帮助我们在Package Manager Console上执行迁移命令时使用。
/// 但是,在运行EF的Migrate.exe时可能会导致问题。 如果要在命令行上应用迁移,请不要将连接字符串名称传递给基类。 ABP工作方式。
/// </summary>
public PMDBContext() : base("Default")
{
}
/// <summary>
/// ABP使用此构造函数传递PMDBContext.PreInitialize中定义的连接字符串。
/// 注意,实际上你不会直接创建一个PMDBContext的实例,因为ABP自动处理它。
/// </summary>
/// <param name="nameOrnameOrConnectionString"></param>
public PMDBContext(string nameOrnameOrConnectionString) : base(nameOrnameOrConnectionString)
{
}
/// <summary>
/// 这个构造函数用于测试
/// </summary>
/// <param name="existingConnection"></param>
public PMDBContext(DbConnection existingConnection) : base(existingConnection,false)
{
}
public PMDBContext(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{
}
}
}
PMDBContext
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Editions;
using PM.Core.Editions;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 默认版本创建者
/// </summary>
public class DefaultEditionsCreator
{
private readonly PMDBContext _context;
public DefaultEditionsCreator(PMDBContext context)
{
_context = context;
}
public void Create()
{
CreateEdtions();
}
private void CreateEdtions()
{
var defaultEdtion = _context.Editions.FirstOrDefault(e => e.Name == EditionManager.DefaultEditionName);
if (defaultEdtion == null)
{
defaultEdtion = new Edition()
{
Name = EditionManager.DefaultEditionName,
DisplayName = EditionManager.DefaultEditionName
};
_context.Editions.Add(defaultEdtion);
_context.SaveChanges();
//TODO:如果需要,可以在标准版中添加所需的功能!
}
}
}
}
DefaultEditionsCreator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Localization;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 默认语言创建者
/// </summary>
public class DefaultLanguagesCreator
{
public static List<ApplicationLanguage> InitialLanguages { get; private set; }
private readonly PMDBContext _context;
static DefaultLanguagesCreator()
{
InitialLanguages = new List<ApplicationLanguage>
{
new ApplicationLanguage(null, "en", "English", "famfamfam-flags gb"),
new ApplicationLanguage(null, "tr", "Türkçe", "famfamfam-flags tr"),
new ApplicationLanguage(null, "zh-CN", "简体中文", "famfamfam-flags cn"),
new ApplicationLanguage(null, "pt-BR", "Português-BR", "famfamfam-flags br"),
new ApplicationLanguage(null, "es", "Español", "famfamfam-flags es"),
new ApplicationLanguage(null, "fr", "Français", "famfamfam-flags fr"),
new ApplicationLanguage(null, "it", "Italiano", "famfamfam-flags it"),
new ApplicationLanguage(null, "ja", "日本語", "famfamfam-flags jp"),
new ApplicationLanguage(null, "nl-NL", "Nederlands", "famfamfam-flags nl"),
new ApplicationLanguage(null, "lt", "Lietuvos", "famfamfam-flags lt"),
new ApplicationLanguage(null, "vn", "Vietnamese", "famfamfam-flags vn")
};
}
public DefaultLanguagesCreator(PMDBContext context)
{
_context = context;
}
public void Create()
{
CreateLanguages();
}
private void CreateLanguages()
{
foreach (var applicationLanguage in InitialLanguages)
{
AddLanguageIfNotExists(applicationLanguage);
}
}
private void AddLanguageIfNotExists(ApplicationLanguage language)
{
if (_context.Languages.Any(l => l.TenantId == language.TenantId && l.Name == language.Name))
{
return;
}
_context.Languages.Add(language);
_context.SaveChanges();
}
}
}
DefaultLanguagesCreator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Configuration;
using Abp.Localization;
using Abp.Net.Mail;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 默认设置创建者
/// </summary>
public class DefaultSettingsCreator
{
private readonly PMDBContext _context;
public DefaultSettingsCreator(PMDBContext context)
{
_context = context;
}
public void Create()
{
//邮箱
AddSettingIfNotExists(EmailSettingNames.DefaultFromAddress, "qq962410314@163.com");
AddSettingIfNotExists(EmailSettingNames.DefaultFromDisplayName, "qq962410314@163.com");
//语言
AddSettingIfNotExists(LocalizationSettingNames.DefaultLanguage, "zh-CN");
}
private void AddSettingIfNotExists(string name, string value, int? tenantId = null)
{
if (_context.Settings.Any(s => s.Name == name && s.TenantId == tenantId && s.UserId == null))
{
return;
}
_context.Settings.Add(new Setting(tenantId, null, name, value));
_context.SaveChanges();
}
}
}
DefaultSettingsCreator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PM.Core.MultiTenant;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 默认租户创建者
/// </summary>
public class DefaultTenantCreator
{
private readonly PMDBContext _context;
public DefaultTenantCreator(PMDBContext context)
{
_context = context;
}
public void Create()
{
CreateUserAndRoles();
}
private void CreateUserAndRoles()
{
//默认租户
var defaultTenant = _context.Tenants.FirstOrDefault(t => t.TenancyName == Tenant.DefaultTenantName);
if (defaultTenant == null)
{
_context.Tenants.Add(new Tenant()
{
TenancyName = Tenant.DefaultTenantName,
Name = Tenant.DefaultTenantName
});
_context.SaveChanges();
}
}
}
}
DefaultTenantCreator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.MultiTenancy;
using Microsoft.AspNet.Identity;
using PM.Core.Authorization;
using PM.Core.Authorization.Roles;
using PM.Core.Users;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 主机admin创建者
/// </summary>
public class HostRoleAndUserCreator
{
private readonly PMDBContext _context;
public HostRoleAndUserCreator(PMDBContext context)
{
_context = context;
}
public void Create()
{
CreateHostRoleAndUsers();
}
private void CreateHostRoleAndUsers()
{
//主机角色
var adminRoleForHost= _context.Roles.FirstOrDefault(r => r.TenantId == null && r.Name == StaticRoleNames.Host.Admin);
if (adminRoleForHost == null)
{
adminRoleForHost = _context.Roles.Add(new Role()
{
Name = StaticRoleNames.Host.Admin,
DisplayName = StaticRoleNames.Host.Admin,
IsStatic = true
});
_context.SaveChanges();
//授予所有租户权限
var permisstions = PermissionFinder.GetAllPermissions(new PMProjectNameAuthorizationProvider())
.Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Host))
.ToList();
foreach (var permisstion in permisstions)
{
_context.Permissions.Add(new RolePermissionSetting()
{
Name = permisstion.Name,
IsGranted = true,
RoleId = adminRoleForHost.Id
});
}
_context.SaveChanges();
}
//主机admin
var adminUserForHost =
_context.Users.FirstOrDefault(u => u.TenantId == null && u.UserName == User.AdminUserName);
if (adminUserForHost == null)
{
adminUserForHost = _context.Users.Add(new User()
{
UserName = User.AdminUserName,
Name = "System",
Surname = "Administrator",
EmailAddress = "qq962410314@163.com",
IsEmailConfirmed = true,
Password = new PasswordHasher().HashPassword(User.DefaultPassword)
});
_context.SaveChanges();
_context.UserRoles.Add(new UserRole(null, adminUserForHost.Id, adminRoleForHost.Id));
_context.SaveChanges();
}
}
}
}
HostRoleAndUserCreator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFramework.DynamicFilters;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 初始化主机数据库提供者
/// </summary>
public class InitialHostDbBuilder
{
private readonly PMDBContext _context;
public InitialHostDbBuilder(PMDBContext context)
{
_context = context;
}
public void Create()
{
//禁用所有过滤器
_context.DisableAllFilters();
new DefaultEditionsCreator(_context).Create();
new DefaultLanguagesCreator(_context).Create();
new HostRoleAndUserCreator(_context).Create();
new DefaultSettingsCreator(_context).Create();
}
}
}
InitialHostDbBuilder
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.MultiTenancy;
using PM.Core.Authorization;
using PM.Core.Authorization.Roles;
using PM.Core.Users;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations.SeedData
{
/// <summary>
/// 租户admin创建者
/// </summary>
public class TenantRoleAndUserBuilder
{
private readonly PMDBContext _context;
private readonly int _tenantId;
public TenantRoleAndUserBuilder(PMDBContext context, int tenantId)
{
_context = context;
_tenantId = tenantId;
}
public void Create()
{
CreateRolesAndUsers();
}
private void CreateRolesAndUsers()
{
//租户角色
var adminRole =
_context.Roles.FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.Admin);
if (adminRole==null)
{
adminRole =
_context.Roles.Add(new Role(_tenantId, StaticRoleNames.Tenants.Admin, StaticRoleNames.Tenants.Admin)
{
IsStatic = true
});
_context.SaveChanges();
//授予管理员角色的所有权限
var permisstions = PermissionFinder.GetAllPermissions(new PMProjectNameAuthorizationProvider())
.Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Tenant))
.ToList();
foreach (var permisstion in permisstions)
{
_context.Permissions.Add(new RolePermissionSetting()
{
TenantId = _tenantId,
Name = permisstion.Name,
IsGranted = true,
RoleId = adminRole.Id
});
}
_context.SaveChanges();
}
//租户admin
var adminUser =
_context.Users.FirstOrDefault(u => u.TenantId == _tenantId && u.UserName == User.AdminUserName);
if (adminUser == null)
{
adminUser = User.CreateTenantAdminUser(_tenantId, "qq962410314@163.com", User.DefaultPassword);
adminUser.IsEmailConfirmed = true;
adminUser.IsActive = true;
_context.Users.Add(adminUser);
_context.SaveChanges();
_context.UserRoles.Add(new UserRole(_tenantId, adminUser.Id, adminRole.Id));
_context.SaveChanges();
}
}
}
}
TenantRoleAndUserBuilder
namespace PM.EntityFramework.Migrations
{
using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.Migrations;
public partial class init : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.AbpAuditLogs",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(),
ServiceName = c.String(maxLength: 256),
MethodName = c.String(maxLength: 256),
Parameters = c.String(maxLength: 1024),
ExecutionTime = c.DateTime(nullable: false),
ExecutionDuration = c.Int(nullable: false),
ClientIpAddress = c.String(maxLength: 64),
ClientName = c.String(maxLength: 128),
BrowserInfo = c.String(maxLength: 256),
Exception = c.String(maxLength: 2000),
ImpersonatorUserId = c.Long(),
ImpersonatorTenantId = c.Int(),
CustomData = c.String(maxLength: 2000),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_AuditLog_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpBackgroundJobs",
c => new
{
Id = c.Long(nullable: false, identity: true),
JobType = c.String(nullable: false, maxLength: 512),
JobArgs = c.String(nullable: false),
TryCount = c.Short(nullable: false),
NextTryTime = c.DateTime(nullable: false),
LastTryTime = c.DateTime(),
IsAbandoned = c.Boolean(nullable: false),
Priority = c.Byte(nullable: false),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
})
.PrimaryKey(t => t.Id)
.Index(t => new { t.IsAbandoned, t.NextTryTime });
CreateTable(
"dbo.AbpFeatures",
c => new
{
Id = c.Long(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 128),
Value = c.String(nullable: false, maxLength: 2000),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
EditionId = c.Int(),
TenantId = c.Int(),
Discriminator = c.String(nullable: false, maxLength: 128),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_TenantFeatureSetting_MustHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpEditions", t => t.EditionId, cascadeDelete: true)
.Index(t => t.EditionId);
CreateTable(
"dbo.AbpEditions",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 32),
DisplayName = c.String(nullable: false, maxLength: 64),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_Edition_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpLanguages",
c => new
{
Id = c.Int(nullable: false, identity: true),
TenantId = c.Int(),
Name = c.String(nullable: false, maxLength: 10),
DisplayName = c.String(nullable: false, maxLength: 64),
Icon = c.String(maxLength: 128),
IsDisabled = c.Boolean(nullable: false),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_ApplicationLanguage_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_ApplicationLanguage_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpLanguageTexts",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
LanguageName = c.String(nullable: false, maxLength: 10),
Source = c.String(nullable: false, maxLength: 128),
Key = c.String(nullable: false, maxLength: 256),
Value = c.String(nullable: false),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_ApplicationLanguageText_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpNotifications",
c => new
{
Id = c.Guid(nullable: false),
NotificationName = c.String(nullable: false, maxLength: 96),
Data = c.String(),
DataTypeName = c.String(maxLength: 512),
EntityTypeName = c.String(maxLength: 250),
EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
EntityId = c.String(maxLength: 96),
Severity = c.Byte(nullable: false),
UserIds = c.String(),
ExcludedUserIds = c.String(),
TenantIds = c.String(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpNotificationSubscriptions",
c => new
{
Id = c.Guid(nullable: false),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
NotificationName = c.String(maxLength: 96),
EntityTypeName = c.String(maxLength: 250),
EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
EntityId = c.String(maxLength: 96),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_NotificationSubscriptionInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.Index(t => new { t.NotificationName, t.EntityTypeName, t.EntityId, t.UserId });
CreateTable(
"dbo.AbpOrganizationUnits",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
ParentId = c.Long(),
Code = c.String(nullable: false, maxLength: 95),
DisplayName = c.String(nullable: false, maxLength: 128),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_OrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_OrganizationUnit_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpOrganizationUnits", t => t.ParentId)
.Index(t => t.ParentId);
CreateTable(
"dbo.AbpPermissions",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
Name = c.String(nullable: false, maxLength: 128),
IsGranted = c.Boolean(nullable: false),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
RoleId = c.Int(),
UserId = c.Long(),
Discriminator = c.String(nullable: false, maxLength: 128),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_PermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_RolePermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_UserPermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
.ForeignKey("dbo.AbpRoles", t => t.RoleId, cascadeDelete: true)
.Index(t => t.RoleId)
.Index(t => t.UserId);
CreateTable(
"dbo.AbpRoles",
c => new
{
Id = c.Int(nullable: false, identity: true),
Description = c.String(),
TenantId = c.Int(),
Name = c.String(nullable: false, maxLength: 32),
DisplayName = c.String(nullable: false, maxLength: 64),
IsStatic = c.Boolean(nullable: false),
IsDefault = c.Boolean(nullable: false),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_Role_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_Role_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
.ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
.ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
.Index(t => t.DeleterUserId)
.Index(t => t.LastModifierUserId)
.Index(t => t.CreatorUserId);
CreateTable(
"dbo.AbpUsers",
c => new
{
Id = c.Long(nullable: false, identity: true),
AuthenticationSource = c.String(maxLength: 64),
UserName = c.String(nullable: false, maxLength: 32),
TenantId = c.Int(),
EmailAddress = c.String(nullable: false, maxLength: 256),
Name = c.String(nullable: false, maxLength: 32),
Surname = c.String(nullable: false, maxLength: 32),
Password = c.String(nullable: false, maxLength: 128),
EmailConfirmationCode = c.String(maxLength: 328),
PasswordResetCode = c.String(maxLength: 328),
LockoutEndDateUtc = c.DateTime(),
AccessFailedCount = c.Int(nullable: false),
IsLockoutEnabled = c.Boolean(nullable: false),
PhoneNumber = c.String(),
IsPhoneNumberConfirmed = c.Boolean(nullable: false),
SecurityStamp = c.String(),
IsTwoFactorEnabled = c.Boolean(nullable: false),
IsEmailConfirmed = c.Boolean(nullable: false),
IsActive = c.Boolean(nullable: false),
LastLoginTime = c.DateTime(),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_User_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_User_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
.ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
.ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
.Index(t => t.DeleterUserId)
.Index(t => t.LastModifierUserId)
.Index(t => t.CreatorUserId);
CreateTable(
"dbo.AbpUserClaims",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
ClaimType = c.String(),
ClaimValue = c.String(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserClaim_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
.Index(t => t.UserId);
CreateTable(
"dbo.AbpUserLogins",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
LoginProvider = c.String(nullable: false, maxLength: 128),
ProviderKey = c.String(nullable: false, maxLength: 256),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserLogin_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
.Index(t => t.UserId);
CreateTable(
"dbo.AbpUserRoles",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
RoleId = c.Int(nullable: false),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserRole_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.UserId, cascadeDelete: true)
.Index(t => t.UserId);
CreateTable(
"dbo.AbpSettings",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(),
Name = c.String(nullable: false, maxLength: 256),
Value = c.String(maxLength: 2000),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_Setting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.UserId)
.Index(t => t.UserId);
CreateTable(
"dbo.AbpTenantNotifications",
c => new
{
Id = c.Guid(nullable: false),
TenantId = c.Int(),
NotificationName = c.String(nullable: false, maxLength: 96),
Data = c.String(),
DataTypeName = c.String(maxLength: 512),
EntityTypeName = c.String(maxLength: 250),
EntityTypeAssemblyQualifiedName = c.String(maxLength: 512),
EntityId = c.String(maxLength: 96),
Severity = c.Byte(nullable: false),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_TenantNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpTenants",
c => new
{
Id = c.Int(nullable: false, identity: true),
EditionId = c.Int(),
Name = c.String(nullable: false, maxLength: 128),
TenancyName = c.String(nullable: false, maxLength: 64),
ConnectionString = c.String(maxLength: 1024),
IsActive = c.Boolean(nullable: false),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_Tenant_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AbpUsers", t => t.CreatorUserId)
.ForeignKey("dbo.AbpUsers", t => t.DeleterUserId)
.ForeignKey("dbo.AbpEditions", t => t.EditionId)
.ForeignKey("dbo.AbpUsers", t => t.LastModifierUserId)
.Index(t => t.EditionId)
.Index(t => t.DeleterUserId)
.Index(t => t.LastModifierUserId)
.Index(t => t.CreatorUserId);
CreateTable(
"dbo.AbpUserAccounts",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
UserLinkId = c.Long(),
UserName = c.String(),
EmailAddress = c.String(),
LastLoginTime = c.DateTime(),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserAccount_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.AbpUserLoginAttempts",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
TenancyName = c.String(maxLength: 64),
UserId = c.Long(),
UserNameOrEmailAddress = c.String(maxLength: 255),
ClientIpAddress = c.String(maxLength: 64),
ClientName = c.String(maxLength: 128),
BrowserInfo = c.String(maxLength: 256),
Result = c.Byte(nullable: false),
CreationTime = c.DateTime(nullable: false),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserLoginAttempt_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.Index(t => new { t.UserId, t.TenantId })
.Index(t => new { t.TenancyName, t.UserNameOrEmailAddress, t.Result });
CreateTable(
"dbo.AbpUserNotifications",
c => new
{
Id = c.Guid(nullable: false),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
TenantNotificationId = c.Guid(nullable: false),
State = c.Int(nullable: false),
CreationTime = c.DateTime(nullable: false),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id)
.Index(t => new { t.UserId, t.State, t.CreationTime });
CreateTable(
"dbo.AbpUserOrganizationUnits",
c => new
{
Id = c.Long(nullable: false, identity: true),
TenantId = c.Int(),
UserId = c.Long(nullable: false),
OrganizationUnitId = c.Long(nullable: false),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserOrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
}
public override void Down()
{
DropForeignKey("dbo.AbpTenants", "LastModifierUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpTenants", "EditionId", "dbo.AbpEditions");
DropForeignKey("dbo.AbpTenants", "DeleterUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpTenants", "CreatorUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpPermissions", "RoleId", "dbo.AbpRoles");
DropForeignKey("dbo.AbpRoles", "LastModifierUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpRoles", "DeleterUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpRoles", "CreatorUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpSettings", "UserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUserRoles", "UserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpPermissions", "UserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUserLogins", "UserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUsers", "LastModifierUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUsers", "DeleterUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUsers", "CreatorUserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpUserClaims", "UserId", "dbo.AbpUsers");
DropForeignKey("dbo.AbpOrganizationUnits", "ParentId", "dbo.AbpOrganizationUnits");
DropForeignKey("dbo.AbpFeatures", "EditionId", "dbo.AbpEditions");
DropIndex("dbo.AbpUserNotifications", new[] { "UserId", "State", "CreationTime" });
DropIndex("dbo.AbpUserLoginAttempts", new[] { "TenancyName", "UserNameOrEmailAddress", "Result" });
DropIndex("dbo.AbpUserLoginAttempts", new[] { "UserId", "TenantId" });
DropIndex("dbo.AbpTenants", new[] { "CreatorUserId" });
DropIndex("dbo.AbpTenants", new[] { "LastModifierUserId" });
DropIndex("dbo.AbpTenants", new[] { "DeleterUserId" });
DropIndex("dbo.AbpTenants", new[] { "EditionId" });
DropIndex("dbo.AbpSettings", new[] { "UserId" });
DropIndex("dbo.AbpUserRoles", new[] { "UserId" });
DropIndex("dbo.AbpUserLogins", new[] { "UserId" });
DropIndex("dbo.AbpUserClaims", new[] { "UserId" });
DropIndex("dbo.AbpUsers", new[] { "CreatorUserId" });
DropIndex("dbo.AbpUsers", new[] { "LastModifierUserId" });
DropIndex("dbo.AbpUsers", new[] { "DeleterUserId" });
DropIndex("dbo.AbpRoles", new[] { "CreatorUserId" });
DropIndex("dbo.AbpRoles", new[] { "LastModifierUserId" });
DropIndex("dbo.AbpRoles", new[] { "DeleterUserId" });
DropIndex("dbo.AbpPermissions", new[] { "UserId" });
DropIndex("dbo.AbpPermissions", new[] { "RoleId" });
DropIndex("dbo.AbpOrganizationUnits", new[] { "ParentId" });
DropIndex("dbo.AbpNotificationSubscriptions", new[] { "NotificationName", "EntityTypeName", "EntityId", "UserId" });
DropIndex("dbo.AbpFeatures", new[] { "EditionId" });
DropIndex("dbo.AbpBackgroundJobs", new[] { "IsAbandoned", "NextTryTime" });
DropTable("dbo.AbpUserOrganizationUnits",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserOrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserNotifications",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserLoginAttempts",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserLoginAttempt_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserAccounts",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserAccount_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpTenants",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_Tenant_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpTenantNotifications",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_TenantNotificationInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpSettings",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_Setting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserRoles",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserRole_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserLogins",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserLogin_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUserClaims",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_UserClaim_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpUsers",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_User_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_User_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpRoles",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_Role_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_Role_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpPermissions",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_PermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_RolePermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_UserPermissionSetting_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpOrganizationUnits",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_OrganizationUnit_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_OrganizationUnit_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpNotificationSubscriptions",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_NotificationSubscriptionInfo_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpNotifications");
DropTable("dbo.AbpLanguageTexts",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_ApplicationLanguageText_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpLanguages",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_ApplicationLanguage_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
{ "DynamicFilter_ApplicationLanguage_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpEditions",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_Edition_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpFeatures",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_TenantFeatureSetting_MustHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
DropTable("dbo.AbpBackgroundJobs");
DropTable("dbo.AbpAuditLogs",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_AuditLog_MayHaveTenant", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
}
}
}
init
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Dependency;
using Abp.Domain.Uow;
using Abp.MultiTenancy;
using Abp.Zero.EntityFramework;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework.Migrations
{
/// <summary>
/// 执行数据库迁移
/// </summary>
public class AbpZeroDbMigrator : AbpZeroDbMigrator<PMDBContext, Configuration>
{
public AbpZeroDbMigrator(IUnitOfWorkManager unitOfWorkManager,
IDbPerTenantConnectionStringResolver connectionStringResolver, IIocResolver iocResolver)
: base(unitOfWorkManager, connectionStringResolver, iocResolver)
{
}
}
}
AbpZeroDbMigrator
using Abp.MultiTenancy;
using Abp.Zero.EntityFramework;
using EntityFramework.DynamicFilters;
using PM.EntityFramework.Migrations.SeedData;
namespace PM.EntityFramework.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
public sealed class Configuration : DbMigrationsConfiguration<PM.EntityFramework.EntityFramework.PMDBContext>,IMultiTenantSeed
{
public AbpTenantBase Tenant { get; set; }
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "PM";
}
//Seed() 方法会在你每次你执行 Update-Database 指令时被呼叫一次
protected override void Seed(PM.EntityFramework.EntityFramework.PMDBContext context)
{
//禁用所有过滤
context.DisableAllFilters();
if (Tenant == null)
{
//主机种子
new InitialHostDbBuilder(context).Create();
//默认租户种子
new DefaultTenantCreator(context).Create();
new TenantRoleAndUserBuilder(context, 1).Create();
}
else
{
//您可以为租户数据库添加种子并使用租户属性...
}
context.SaveChanges();
}
}
}
Configuration
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Abp.Modules;
using Abp.Zero.EntityFramework;
using PM.Core;
using PM.EntityFramework.EntityFramework;
namespace PM.EntityFramework
{
[DependsOn(typeof(PMCoreModule),typeof(AbpZeroEntityFrameworkModule))]
public class PMDataModule:AbpModule
{
public override void PreInitialize()
{
Database.SetInitializer(new CreateDatabaseIfNotExists<PMDBContext>());
Configuration.DefaultNameOrConnectionString = "Default";
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
}
PMDataModule
四、PM.Application
1,NuGet安装Abp.Zero2.1.3、Abp.AutoMapper2.1.3
程序集引用:System.ComponentModel.DataAnnotations
2,基本结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.IdentityFramework;
using Abp.Runtime.Session;
using Microsoft.AspNet.Identity;
using PM.Core;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Application
{
public class PMAppServiceBase:ApplicationService
{
public TenantManager TenantManager { get; set; }
public UserManager UserManager { get; set; }
protected PMAppServiceBase()
{
LocalizationSourceName = PMProjectNameConsts.LocalizationSourceName;
}
protected virtual Task<User> GetCurrentUserAsync()
{
var user= UserManager.FindByIdAsync(AbpSession.GetUserId());
if (user == null)
{
throw new ApplicationException("目前没有用户!");
}
return user;
}
protected virtual Task<Tenant> GetCurrentTenantAsync()
{
return TenantManager.GetByIdAsync(AbpSession.GetTenantId());
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}
PMAppServiceBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.AutoMapper;
using Abp.Modules;
using PM.Application.Roles.Dto;
using PM.Application.Users.Dto;
using PM.Core;
using PM.Core.Authorization.Roles;
using PM.Core.Users;
namespace PM.Application
{
[DependsOn(typeof(PMCoreModule),typeof(AbpAutoMapperModule))]
public class PMApplicationModule:AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
{
// Role and permission
cfg.CreateMap<Permission, string>().ConvertUsing(r => r.Name);
cfg.CreateMap<RolePermissionSetting, string>().ConvertUsing(r => r.Name);
cfg.CreateMap<CreateRoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
cfg.CreateMap<RoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
cfg.CreateMap<UserDto, User>();
cfg.CreateMap<UserDto, User>().ForMember(x => x.Roles, opt => opt.Ignore());
cfg.CreateMap<CreateUserDto, User>();
cfg.CreateMap<CreateUserDto, User>().ForMember(x => x.Roles, opt => opt.Ignore());
});
}
}
}
PMApplicationModule
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Zero.Configuration;
using PM.Application.Authorization.Accounts.Dto;
using PM.Core.Authorization.Users;
using Abp.Configuration;
namespace PM.Application.Authorization.Accounts
{
public class AccountAppService:PMAppServiceBase,IAccountAppService
{
private readonly UserRegistrationManager _userRegistrationManager;
public AccountAppService(UserRegistrationManager userRegistrationManager)
{
_userRegistrationManager = userRegistrationManager;
}
public async Task<IsTenantAvaliableOutput> IsTenantAvaliable(IsTenantAvaliableInput input)
{
var tenant = await TenantManager.FindByTenancyNameAsync(input.TenantName);
if (tenant == null)
{
return new IsTenantAvaliableOutput(TenantAvaliablityState.NotFound);
}
if (!tenant.IsActive)
{
return new IsTenantAvaliableOutput(TenantAvaliablityState.InActive);
}
return new IsTenantAvaliableOutput(TenantAvaliablityState.Avaliable, tenant.Id);
}
public async Task<RegisterOutput> Register(RegisterInput input)
{
var user =await _userRegistrationManager.RegisterAsync(input.Name, input.Surname, input.EmailAddress,
input.UserName,
input.Password, false);
//电子邮件确认需要登录
var isEmailConfirmationRequiredForLogin = await SettingManager.GetSettingValueAsync<bool>(
AbpZeroSettingNames.UserManagement.IsEmailConfirmationRequiredForLogin);
return new RegisterOutput()
{
CanLogin = user.IsActive && (user.IsEmailConfirmed || !isEmailConfirmationRequiredForLogin)
};
}
}
}
AccountAppService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Runtime.Session;
using PM.Application.Configuration.Dto;
using PM.Core.Configuration;
namespace PM.Application.Configuration
{
public class ConfigurationAppService : PMAppServiceBase, IConfigurationAppService
{
public async Task ChangeUiTheme(ChangeUiThemeInput input)
{
await
SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), PMSettingNames.UiTheme,
input.Theme);
}
}
}
ConfigurationAppService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Microsoft.AspNet.Identity;
using PM.Application.MultiTenancy.Dto;
using PM.Core.Authorization.Roles;
using PM.Core.Editions;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Application.MultiTenancy
{
public class TenantAppService : AsyncCrudAppService<Tenant, TenantDto, int, PagedResultRequestDto, CreateTenantDto, TenantDto>, ITenantAppService
{
private readonly TenantManager _tenantManager;
private readonly EditionManager _editionManager;
private readonly UserManager _userManager;
private readonly RoleManager _roleManager;
private readonly IAbpZeroDbMigrator _abpZeroDbMigrator;
public TenantAppService(
IRepository<Tenant, int> repository,
TenantManager tenantManager,
EditionManager editionManager,
UserManager userManager,
RoleManager roleManager,
IAbpZeroDbMigrator abpZeroDbMigrator
) : base(repository)
{
_editionManager = editionManager;
_tenantManager = tenantManager;
_userManager = userManager;
_roleManager = roleManager;
_abpZeroDbMigrator = abpZeroDbMigrator;
}
private void CheckError(IdentityResult identityResult)
{
identityResult.CheckErrors();
}
/// <summary>
/// 创建租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public override async Task<TenantDto> Create(CreateTenantDto input)
{
//判断是否已拥有此接口的权限(Create方法),需要赋值CreatePermissionName属性
CheckCreatePermission();
var tenant = input.MapTo<Tenant>();
//加密数据库链接字符串(采用AES对称加密)
tenant.ConnectionString = input.ConnectionString.IsNullOrEmpty()
? null
: SimpleStringCipher.Instance.Encrypt(input.ConnectionString);
//当前租户使用的版本(Standard标准版)
var defaultEdition = await _editionManager.FindByNameAsync(EditionManager.DefaultEditionName);
if (defaultEdition != null)
{
tenant.EditionId = defaultEdition.Id;
}
//创建租户
await _tenantManager.CreateAsync(tenant);
//获得租户的id
await CurrentUnitOfWork.SaveChangesAsync();
//创建租户数据库
_abpZeroDbMigrator.CreateOrMigrateForTenant(tenant);
using (CurrentUnitOfWork.SetTenantId(tenant.Id))
{
//创建静态租户角色,该静态角色通过IRoleManagementConfig配置
CheckError(await _roleManager.CreateStaticRoles(tenant.Id));
await CurrentUnitOfWork.SaveChangesAsync();//获取静态角色id
//授予管理员角色所有权限(该权限通过IPermissionDefinitionContext配置)
var adminRole = _roleManager.Roles.Single(r => r.Name == StaticRoleNames.Tenants.Admin);
await _roleManager.GrantAllPermissionsAsync(adminRole);
//创建租户admin用户
var adminUser= User.CreateTenantAdminUser(tenant.Id, input.AdminEmailAddress, User.DefaultPassword);
CheckError(await _userManager.CreateAsync(adminUser));
await CurrentUnitOfWork.SaveChangesAsync();//获取用户id
//讲角色分配给租户admin用户
CheckError(await _userManager.AddToRoleAsync(adminUser.Id, adminRole.Name));
await CurrentUnitOfWork.SaveChangesAsync();
}
return MapToEntityDto(tenant);
}
protected override void MapToEntity(TenantDto updateInput, Tenant entity)
{
//手动映射,因为TenantDto也包含不可编辑的属性。
entity.Name = updateInput.Name;
entity.TenancyName = updateInput.TenancyName;
entity.IsActive = updateInput.IsActive;
}
public override async Task Delete(EntityDto<int> input)
{
CheckDeletePermission();
var tenant =await _tenantManager.FindByIdAsync(input.Id);
await _tenantManager.DeleteAsync(tenant);
}
}
}
TenantAppService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.IdentityFramework;
using Abp.UI;
using Microsoft.AspNet.Identity;
using PM.Application.Roles.Dto;
using PM.Core.Authorization.Roles;
using PM.Core.MultiTenant;
using PM.Core.Users;
namespace PM.Application.Roles
{
public class RoleAppService:AsyncCrudAppService<Role,RoleDto,Int32,PagedResultRequestDto,CreateRoleDto,RoleDto>,IRoleAppService
{
private readonly RoleManager _roleManager;
private readonly UserManager _userManager;
private readonly IRepository<User, long> _userRepository;
private readonly IRepository<UserRole, long> _userRoleRepository;
private readonly IRepository<Role> _roleRepository;
public RoleAppService(
IRepository<Role, int> repository,
RoleManager roleManager,
UserManager userManager,
IRepository<User,long> userRepository,
IRepository<UserRole,long> userRoleRepository,
IRepository<Role> roleRepository
) : base(repository)
{
_roleManager = roleManager;
_userManager = userManager;
_userRepository = userRepository;
_userRoleRepository = userRoleRepository;
_roleRepository = roleRepository;
}
public override async Task<RoleDto> Create(CreateRoleDto input)
{
CheckCreatePermission();
var role = input.MapTo<Role>();
CheckErrors(await _roleManager.CreateAsync(role));
//查询权限
var grantedPermissions =
PermissionManager.GetAllPermissions().Where(p => input.Permissions.Contains(p.Name)).ToList();
//给角色设置权限
await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
return MapToEntityDto(role);
}
public override async Task Delete(EntityDto<int> input)
{
CheckDeletePermission();
var role = await _roleManager.FindByIdAsync(input.Id);
if (role.IsStatic)
{
throw new UserFriendlyException("无法删除静态角色");
}
//删除用户角色关联
var users = await GetUsersInRoleAsync(role.Name);
foreach (var user in users)
{
CheckErrors(await _userManager.RemoveFromRoleAsync(user, role.Name));
}
//删除角色
await _roleManager.DeleteAsync(role);
}
private Task<List<long>> GetUsersInRoleAsync(string roleName)
{
var users= (from user in _userRepository.GetAll()
join userRole in _userRoleRepository.GetAll() on user.Id equals userRole.UserId
join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id
where role.Name == roleName
select user.Id).Distinct().ToList();
return Task.FromResult(users);
}
public Task<ListResultDto<PermissionDto>> GetAllPermissions()
{
var permissions = PermissionManager.GetAllPermissions();
return Task.FromResult(new ListResultDto<PermissionDto>(permissions.MapTo<List<PermissionDto>>()));
}
protected override Task<Role> GetEntityByIdAsync(int id)
{
//查询角色,并包含该角色的权限
var role = Repository.GetAllIncluding(x => x.Permissions).FirstOrDefault(x => x.Id == id);
return Task.FromResult(role);
}
/// <summary>
/// 创建过滤查询
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
protected override IQueryable<Role> CreateFilteredQuery(PagedResultRequestDto input)
{
return Repository.GetAllIncluding(x => x.Permissions);
}
/// <summary>
/// 应用排序
/// </summary>
/// <param name="query"></param>
/// <param name="input"></param>
/// <returns></returns>
protected override IQueryable<Role> ApplySorting(IQueryable<Role> query, PagedResultRequestDto input)
{
return query.OrderBy(r => r.DisplayName);
}
private void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}
RoleAppService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Auditing;
using Abp.AutoMapper;
using PM.Application.Sessions.Dto;
namespace PM.Application.Sessions
{
public class SessionAppService:PMAppServiceBase,ISessionAppService
{
[DisableAuditing]
public async Task<GetCurrentLoginInformationsOutput> GetCurrentLoginInformations()
{
var output=new GetCurrentLoginInformationsOutput();
if (AbpSession.UserId.HasValue)
{
output.User = (await GetCurrentUserAsync()).MapTo<UserLoginInfoDto>();
}
if (AbpSession.TenantId.HasValue)
{
output.Tenant = (await GetCurrentTenantAsync()).MapTo<TenantLoginInfoDto>();
}
return output;
}
}
}
SessionAppService
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.IdentityFramework;
using Microsoft.AspNet.Identity;
using PM.Application.Roles.Dto;
using PM.Application.Users.Dto;
using PM.Core.Authorization.Roles;
using PM.Core.Users;
namespace PM.Application.Users
{
public class UserAppService:AsyncCrudAppService<User,UserDto,long,PagedResultRequestDto,CreateUserDto,UpdateUserDto>,IUserAppService
{
private readonly UserManager _userManager;
private readonly IRepository<Role> _roleRepository;
private readonly RoleManager _roleManager;
public UserAppService(
IRepository<User, long> repository,
UserManager userManager,
IRepository<Role> roleRepository,
RoleManager roleManager
) : base(repository)
{
_userManager = userManager;
_roleRepository = roleRepository;
_roleManager = roleManager;
}
public override async Task<UserDto> Get(EntityDto<long> input)
{
var user = await base.Get(input);
var userRoles = await _userManager.GetRolesAsync(user.Id);
user.Roles = userRoles.ToArray();
return user;
}
public override async Task<UserDto> Create(CreateUserDto input)
{
CheckCreatePermission();
var user = input.MapTo<User>();
user.TenantId = AbpSession.TenantId;
user.Password = new PasswordHasher().HashPassword(input.Password);
user.IsEmailConfirmed = true;
//分配角色(从租户的所有)
user.Roles = new Collection<UserRole>();
foreach (var roleName in input.RoleNames)
{
var role = await _roleManager.GetRoleByNameAsync(roleName);
user.Roles.Add(new UserRole(AbpSession.TenantId, user.Id, role.Id));
}
CheckErrors(await _userManager.CreateAsync(user));
return MapToEntityDto(user);
}
public override async Task<UserDto> Update(UpdateUserDto input)
{
CheckUpdatePermission();
var user = await _userManager.GetUserByIdAsync(input.Id);
//把有变动的属性赋值到user对象中
MapToEntity(input, user);
CheckErrors(await _userManager.UpdateAsync(user));
if (input.RoleNames != null)
{
//_userManager.SetRoles方法的作用:变更角色(前提:用户表以已经创建)
CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
}
return await Get(input);
}
public override async Task Delete(EntityDto<long> input)
{
var user = await _userManager.GetUserByIdAsync(input.Id);
//admin用户不能被删除(删除用户的同时会删除UserRole)
await _userManager.DeleteAsync(user);
}
public async Task<ListResultDto<RoleDto>> GetRoles()
{
var roles = await _roleRepository.GetAllListAsync();
return new ListResultDto<RoleDto>(roles.MapTo<List<RoleDto>>());
}
protected override User MapToEntity(CreateUserDto createInput)
{
var user = ObjectMapper.Map<User>(createInput);
return user;
}
protected override void MapToEntity(UpdateUserDto updateInput, User entity)
{
ObjectMapper.Map(updateInput, entity);
}
protected override IQueryable<User> CreateFilteredQuery(PagedResultRequestDto input)
{
return Repository.GetAllIncluding(x => x.Roles);
}
protected override async Task<User> GetEntityByIdAsync(long id)
{
var user = Repository.GetAllIncluding(x => x.Roles).FirstOrDefault(x => x.Id == id);
return await Task.FromResult(user);
}
protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedResultRequestDto input)
{
return query.OrderBy(r => r.UserName);
}
private void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}
UserAppService
五、PM.WebApi
1,NuGet安装:
Abp.Zero、Abp.Web.Api、Abp.AutoMapper、Microsoft.Owin.Security.OAuth、Microsoft.AspNet.WebApi.Owin
System.ComponentModel.DataAnnotations
2,WebApiModule
using System.Web.Http;
using Abp.Application.Services;
using Abp.Configuration.Startup;
using Abp.Modules;
using Abp.WebApi;
namespace MyPassword.Api
{
[DependsOn(typeof(AbpWebApiModule), typeof(MyPasswordApplicationModule))]
public class MyPasswordWebApiModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder
.ForAll<IApplicationService>(typeof(MyPasswordApplicationModule).Assembly, "app")
.Build();
//添加访问令牌类型(Access Token Types)过滤(不加这句话也支持Bearer)
Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new HostAuthenticationFilter("Bearer"));
}
}
}
备注:访问令牌类型(Access Token Types)包括bearer类型或mac类型。
①bearer类型
[RFC6750]中定义的“bearer”令牌类型被简单地包含在请求中的访问令牌字符串中:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
②mac类型
而[OAuth-HTTP-MAC]中定义的“mac”令牌类型是通过发送消息认证码(MAC)密钥与用于签署HTTP请求的某些组件的访问令牌一起使用的:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
3,AccountController(获取访问令牌)
using System;
using System.Threading.Tasks;
using System.Web.Http;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.UI;
using Abp.Web.Models;
using Abp.WebApi.Controllers;
using MyPassword.Api.Models;
using MyPassword.Authorization;
using MyPassword.Authorization.Users;
using MyPassword.MultiTenancy;
using MyPassword.Users;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
namespace MyPassword.Api.Controllers
{
public class AccountController : AbpApiController
{
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
private readonly LogInManager _logInManager;
static AccountController()
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
}
public AccountController(LogInManager logInManager)
{
_logInManager = logInManager;
LocalizationSourceName = MyPasswordConsts.LocalizationSourceName;
}
//获取访问令牌
[HttpPost]
public async Task<AjaxResponse> Authenticate(LoginModel loginModel)
{
CheckModelState();
var loginResult = await GetLoginResultAsync(
loginModel.UsernameOrEmailAddress,
loginModel.Password,
loginModel.TenancyName
);
var ticket = new AuthenticationTicket(loginResult.Identity, new AuthenticationProperties());
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
return new AjaxResponse(OAuthBearerOptions.AccessTokenFormat.Protect(ticket));
}
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
{
var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
}
}
private Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName)
{
switch (result)
{
case AbpLoginResultType.Success:
return new ApplicationException("Don't call this method with a success result!");
case AbpLoginResultType.InvalidUserNameOrEmailAddress:
case AbpLoginResultType.InvalidPassword:
return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));
case AbpLoginResultType.InvalidTenancyName:
return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
case AbpLoginResultType.TenantIsNotActive:
return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));
case AbpLoginResultType.UserIsNotActive:
return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
case AbpLoginResultType.UserEmailIsNotConfirmed:
return new UserFriendlyException(L("LoginFailed"), "Your email address is not confirmed. You can not login"); //TODO: localize message
default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
Logger.Warn("Unhandled login fail reason: " + result);
return new UserFriendlyException(L("LoginFailed"));
}
}
protected virtual void CheckModelState()
{
if (!ModelState.IsValid)
{
throw new UserFriendlyException("Invalid request!");
}
}
}
}
AccountController
4,Web工程下的Startup.cs
app.UseOAuthBearerAuthentication(AccountController.OAuthBearerOptions);
将Bearer Token处理添加到OWIN应用程序管道。
这个中间件理解适当的格式化和安全的令牌出现在请求头。
如果Options.AuthenticationMode处于Active状态,则不记名令牌(bearer token)中的声明将被添加到当前请求的IPrincipal用户。
如果Options.AuthenticationMode是Passive的,那么当前请求不被修改,但IAuthenticationManager AuthenticateAsync可以随时用来从请求的不记名令牌(bearer token)中获得请求。
另见http://tools.ietf.org/html/rfc6749
5,案例
请求授权接口
返回令牌
请求受保护的资源
六、PM.Web(MPA)
1,NuGet安装:Abp.Zero、Abp.EntityFramework、Abp.Zero.EntityFramework、Abp.Web.Api、Abp.Web.Mvc、Abp.AutoMapper、Abp.Castle.Log4Net、Abp.Owin
可选则安装:Abp.Web.SignalR
注意,先安装Abp.EntityFramework再安装Abp.Zero.EntityFramework
针对通用的依赖类型的解析与创建,微软默认定义了4种类别的生命周期,分别如下:
类型 | 描述 |
Instance | 任何时间都只能使用特定的实例对象,开发人员需要负责该对象的初始化工作。 |
Transient | 每次都重新创建一个实例。 |
Singleton | 创建一个单例,以后每次调用的时候都返回该单例对象。 |
Scoped | 在当前作用域内,不管调用多少次,都是一个实例,换了作用域就会再次创建实例,类似于特定作用内的单例。 |
前端笔记
1,按钮
<button type="button" class="btn btn-primary btn-circle waves-effect waves-circle waves-float" data-toggle="modal"><i class="material-icons">add</i></button>
btn-circle:圆形按钮
pull-right:右浮动
waves-effect:点击按钮波浪效果
waves-block:块状效果
waves-circle:圆状效果
waves-float:效果浮动
2, 模态框
<a href="#" class="waves-effect waves-block edit-role" data-role-id="@role.Id" data-toggle="modal" data-target="#RoleEditModal"><i class="material-icons">edit</i>@L("Edit")</a>
<div class="modal fade" id="RoleEditModal" tabindex="-1" role="dialog" aria-labelledby="RoleEditModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
<div class="modal fade" id="RoleCreateModal" tabindex="-1" role="dialog" aria-labelledby="RoleCreateModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">
<span>@L("CreateNewRole")</span>
</h4>
</div>
<div class="modal-body">
<form name="roleCreateForm" role="form" novalidate class="form-validation">
<div class="row clearfix">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="rolename" type="text" name="Name" required maxlength="32" minlength="2" class="validate form-control">
<label for="rolename" class="form-label">@L("RoleName")</label>
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="displayname" type="text" name="DisplayName" required maxlength="32" minlength="2" class="validate form-control">
<label for="displayname" class="form-label">@L("DisplayName")</label>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<textarea id="role-description" name="Description" class="validate form-control"></textarea>
<label for="role-description" class="form-label">Role Description</label>
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-12">
<h4>Permissions</h4>
@foreach (var permission in Model.Permissions)
{
<div class="col-sm-6">
<input type="checkbox" name="permission" value="@permission.Name" class="filled-in" id="@string.Format("permission{0}",permission.Name)" checked="checked" />
<label for="@string.Format("permission{0}",permission.Name)">@permission.DisplayName</label>
</div>
}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default waves-effect" data-dismiss="modal">@L("Cancel")</button>
<button type="submit" class="btn btn-primary waves-effect">@L("Save")</button>
</div>
</form>
</div>
</div>
</div>
</div>
View Code
3,for属性
在用户注册的时候,常常用户点击文字就需要将光标聚焦到对应的表单上面,这个是怎么实现的呢?就是下面我要介绍的<label>标签的for属性
定义:for 属性规定 label 与哪个表单元素绑定
<div class="form-line">
<input id="rolename" type="text" name="Name" required maxlength="32" minlength="2" class="validate form-control">
<label for="rolename" class="form-label">@L("RoleName")</label>
</div>
七、PM.Web(SPA)
八、单元测试
1,NuGet安装:
Abp.TestBase、Abp.EntityFramework、Effort.EF6、xunit、Shouldly、xunit.runner.visualstudio、Abp.Zero.EntityFramework、NSubstitute
2,基本结构
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp;
using Abp.Configuration.Startup;
using Abp.Domain.Uow;
using Abp.Runtime.Session;
using Abp.TestBase;
using Castle.MicroKernel.Registration;
using Effort;
using EntityFramework.DynamicFilters;
using PM.Core.MultiTenant;
using PM.Core.Users;
using PM.EntityFramework.EntityFramework;
using PM.EntityFramework.Migrations.SeedData;
namespace PM.Test
{
public class PMTestBase: AbpIntegratedTestBase<PMTestModule>
{
private DbConnection _hostDb;
private Dictionary<int, DbConnection> _tenantDbs; //only used for db per tenant architecture
protected PMTestBase()
{
//Seed initial data for host
AbpSession.TenantId = null;
UsingDbContext(context =>
{
new InitialHostDbBuilder(context).Create();
new DefaultTenantCreator(context).Create();
});
//Seed initial data for default tenant
AbpSession.TenantId = 1;
UsingDbContext(context =>
{
new TenantRoleAndUserBuilder(context, 1).Create();
});
LoginAsDefaultTenantAdmin();
}
protected override void PreInitialize()
{
base.PreInitialize();
/* You can switch database architecture here: */
UseSingleDatabase();
//UseDatabasePerTenant();
}
/* Uses single database for host and all tenants.
*/
private void UseSingleDatabase()
{
_hostDb = DbConnectionFactory.CreateTransient();
LocalIocManager.IocContainer.Register(
Component.For<DbConnection>()
.UsingFactoryMethod(() => _hostDb)
.LifestyleSingleton()
);
}
/* Uses single database for host and Default tenant,
* but dedicated databases for all other tenants.
*/
private void UseDatabasePerTenant()
{
_hostDb = DbConnectionFactory.CreateTransient();
_tenantDbs = new Dictionary<int, DbConnection>();
LocalIocManager.IocContainer.Register(
Component.For<DbConnection>()
.UsingFactoryMethod((kernel) =>
{
lock (_tenantDbs)
{
var currentUow = kernel.Resolve<ICurrentUnitOfWorkProvider>().Current;
var abpSession = kernel.Resolve<IAbpSession>();
var tenantId = currentUow != null ? currentUow.GetTenantId() : abpSession.TenantId;
if (tenantId == null || tenantId == 1) //host and default tenant are stored in host db
{
return _hostDb;
}
if (!_tenantDbs.ContainsKey(tenantId.Value))
{
_tenantDbs[tenantId.Value] = DbConnectionFactory.CreateTransient();
}
return _tenantDbs[tenantId.Value];
}
}, true)
.LifestyleTransient()
);
}
#region UsingDbContext
protected IDisposable UsingTenantId(int? tenantId)
{
var previousTenantId = AbpSession.TenantId;
AbpSession.TenantId = tenantId;
return new DisposeAction(() => AbpSession.TenantId = previousTenantId);
}
protected void UsingDbContext(Action<PMDBContext> action)
{
UsingDbContext(AbpSession.TenantId, action);
}
protected Task UsingDbContextAsync(Func<PMDBContext, Task> action)
{
return UsingDbContextAsync(AbpSession.TenantId, action);
}
protected T UsingDbContext<T>(Func<PMDBContext, T> func)
{
return UsingDbContext(AbpSession.TenantId, func);
}
protected Task<T> UsingDbContextAsync<T>(Func<PMDBContext, Task<T>> func)
{
return UsingDbContextAsync(AbpSession.TenantId, func);
}
protected void UsingDbContext(int? tenantId, Action<PMDBContext> action)
{
using (UsingTenantId(tenantId))
{
using (var context = LocalIocManager.Resolve<PMDBContext>())
{
context.DisableAllFilters();
action(context);
context.SaveChanges();
}
}
}
protected async Task UsingDbContextAsync(int? tenantId, Func<PMDBContext, Task> action)
{
using (UsingTenantId(tenantId))
{
using (var context = LocalIocManager.Resolve<PMDBContext>())
{
context.DisableAllFilters();
await action(context);
await context.SaveChangesAsync();
}
}
}
protected T UsingDbContext<T>(int? tenantId, Func<PMDBContext, T> func)
{
T result;
using (UsingTenantId(tenantId))
{
using (var context = LocalIocManager.Resolve<PMDBContext>())
{
context.DisableAllFilters();
result = func(context);
context.SaveChanges();
}
}
return result;
}
protected async Task<T> UsingDbContextAsync<T>(int? tenantId, Func<PMDBContext, Task<T>> func)
{
T result;
using (UsingTenantId(tenantId))
{
using (var context = LocalIocManager.Resolve<PMDBContext>())
{
context.DisableAllFilters();
result = await func(context);
await context.SaveChangesAsync();
}
}
return result;
}
#endregion
#region Login
protected void LoginAsHostAdmin()
{
LoginAsHost(User.AdminUserName);
}
protected void LoginAsDefaultTenantAdmin()
{
LoginAsTenant(Tenant.DefaultTenantName, User.AdminUserName);
}
protected void LogoutAsDefaultTenant()
{
LogoutAsTenant(Tenant.DefaultTenantName);
}
protected void LoginAsHost(string userName)
{
AbpSession.TenantId = null;
var user =
UsingDbContext(
context =>
context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName));
if (user == null)
{
throw new Exception("There is no user: " + userName + " for host.");
}
AbpSession.UserId = user.Id;
}
protected void LogoutAsHost()
{
Resolve<IMultiTenancyConfig>().IsEnabled = true;
AbpSession.TenantId = null;
AbpSession.UserId = null;
}
protected void LoginAsTenant(string tenancyName, string userName)
{
var tenant = UsingDbContext(context => context.Tenants.FirstOrDefault(t => t.TenancyName == tenancyName));
if (tenant == null)
{
throw new Exception("There is no tenant: " + tenancyName);
}
AbpSession.TenantId = tenant.Id;
var user =
UsingDbContext(
context =>
context.Users.FirstOrDefault(u => u.TenantId == AbpSession.TenantId && u.UserName == userName));
if (user == null)
{
throw new Exception("There is no user: " + userName + " for tenant: " + tenancyName);
}
AbpSession.UserId = user.Id;
}
protected void LogoutAsTenant(string tenancyName)
{
var tenant = UsingDbContext(context => context.Tenants.FirstOrDefault(t => t.TenancyName == tenancyName));
if (tenant == null)
{
throw new Exception("There is no tenant: " + tenancyName);
}
AbpSession.TenantId = tenant.Id;
AbpSession.UserId = null;
}
#endregion
/// <summary>
/// Gets current user if <see cref="IAbpSession.UserId"/> is not null.
/// Throws exception if it's null.
/// </summary>
protected async Task<Core.Users.User> GetCurrentUserAsync()
{
var userId = AbpSession.GetUserId();
return await UsingDbContext(context => context.Users.SingleAsync(u => u.Id == userId));
}
/// <summary>
/// Gets current tenant if <see cref="IAbpSession.TenantId"/> is not null.
/// Throws exception if there is no current tenant.
/// </summary>
protected async Task<Tenant> GetCurrentTenantAsync()
{
var tenantId = AbpSession.GetTenantId();
return await UsingDbContext(context => context.Tenants.SingleAsync(t => t.Id == tenantId));
}
}
}
PMTestBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Modules;
using Abp.MultiTenancy;
using Abp.TestBase;
using Abp.Zero.Configuration;
using Castle.MicroKernel.Registration;
using NSubstitute;
using PM.Application;
using PM.EntityFramework;
namespace PM.Test
{
[DependsOn(
typeof(PMDataModule),
typeof(PMApplicationModule),
typeof(AbpTestBaseModule)
)]
public class PMTestModule:AbpModule
{
public override void PreInitialize()
{
//使用数据库进行语言管理
Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();
//注册伪服务
IocManager.IocContainer.Register(
Component.For<IAbpZeroDbMigrator>()
.UsingFactoryMethod(() => Substitute.For<IAbpZeroDbMigrator>())
.LifestyleSingleton()
);
}
}
}
PMTestModule
using Xunit;
namespace AbpCompanyName.AbpProjectName.Tests
{
public sealed class MultiTenantFactAttribute : FactAttribute
{
public MultiTenantFactAttribute()
{
if (!AbpProjectNameConsts.MultiTenancyEnabled)
{
Skip = "MultiTenancy is disabled.";
}
}
}
}
MultiTenantFactAttribute