上一篇文章中介绍了如何下载、运行ABP Zero示例项目,这个示例项目可以直接作为模板进行二次开发,很适合做企业开发框架。

本未介绍基于ABP Zero示例项目,如何新建一个自定义的实体。

此处已EquipmentType(设备类型)为例,建立一个简单的实体。

以下是之前添加一个简单实体类的效果:

主页

公司列表

新建公司

编辑公司

删除公司


建立方法

按ABP的标准格式,完整建立一个实体,映射到数据库,作为一个基础资料,并通过前端进行增删查改功能,最小步骤如下:

  1. 新增实体类。
  2. 添加数据库映射。
  3. 同步到数据库。
  4. 新建Dto,建立Dto与实体类的映射。
  5. 建立实体类的功能接口(增删查改),并实现接口。
  6. 添加视图模型ViewModel。
  7. 添加控制器。
  8. 添加视图。
  9. 添加js脚本。
  10. 添加前端菜单(入口)。
  11. 添加权限管理。

1. 添加实体类

 namespace oMES_APServer.Equipments
{
public class EquipmentType : MESBase.MESBaseEntity
{ }
}

这里我把MES会用到的常规属性单独建了一个基类,并继承ABP全属性基类FullAuditedEntity

 using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using System.ComponentModel.DataAnnotations; namespace oMES_APServer.MESBase
{
public class MESBaseEntity : FullAuditedEntity<int>, IPassivable
{ public const int MaxCodeLength = ;
public const int MaxNameLength = ;
public const int MaxBriefNameLength = ;
public const int MaxRemarkLength = ; [Required]
[StringLength(MaxCodeLength)]
public string Code { get; set; } [Required]
[StringLength(MaxNameLength)]
public string Name { get; set; } [StringLength()]
public string BriefName { get; set; } [StringLength()]
public string Remark { get; set; }
public bool IsActive { get; set; } }
}

2. 添加数据库映射

添加以下代码:为了让EFCore能够自动生成数据库表结构。

public DbSet<EquipmentType> equipmentTypes { get; set; }

modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType").HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code");

其中.HasAlternateKey表示建立唯一键,.HasName表示键的名称。

 using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using oMES_APServer.Authorization.Roles;
using oMES_APServer.Authorization.Users;
using oMES_APServer.MultiTenancy;
using oMES_APServer.Companies;
using oMES_APServer.Equipments; namespace oMES_APServer.EntityFrameworkCore
{
public class oMES_APServerDbContext : AbpZeroDbContext<Tenant, Role, User, oMES_APServerDbContext>
{
/* Define a DbSet for each entity of the application */
public oMES_APServerDbContext(DbContextOptions<oMES_APServerDbContext> options)
: base(options)
{
} /*添加自定义实体类的数据库映射*/
public DbSet<Company> companies { get; set; }
public DbSet<Department> departments { get; set; }
public DbSet<EquipmentType> equipmentTypes { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<Company>().ToTable("Company")
.HasAlternateKey(x=>x.Code).HasName("UK_Company_Code");
modelBuilder.Entity<Department>().ToTable("Department")
.HasAlternateKey(x => x.Code).HasName("UK_Department_Code");
modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType")
.HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code");
} }
}

3. 同步到数据库。

依次执行以下两条指令:

  1. add-migration add-EquipmentType
  2. update-database

第一条表示,新建同步映射,映射名称为add-EquipmentType。

第二条表示同步数据库。

执行时,出现上述报错,不要慌,重新生成一下项目,应该有报错,解决完项目报错再执行,就可以了。

4. 新建Dto,建立Dto与实体类的映射

建立Dto

 namespace oMES_APServer.Equipments.Dto
{
public class EquipmentTypeDto : MESBaseDto.MESBaseEntityDto
{ }
}

建立实体类和Dto的映射

 using AutoMapper;

 namespace oMES_APServer.Equipments.Dto
{
public class EquipmentTypeMapProfile : Profile
{
public EquipmentTypeMapProfile()
{
CreateMap<EquipmentType, EquipmentTypeDto>();
CreateMap<EquipmentTypeDto, EquipmentType>();
CreateMap<EquipmentTypeDto, EquipmentType>()
.ForMember(x => x.CreationTime, opt => opt.Ignore());
}
}
}

引申:

ABP Zero的Dto类文件夹中,会有一个 PagedxxxResultRequestDto.cs类,这个是用于按给定条件查找数据列表,并进行分页的类。目前还没有学习到,所以仅按照现有的实体类进行仿照编程,不做额外处理。

 using Abp.Application.Services.Dto;

 namespace oMES_APServer.Equipments.Dto
{
public class PagedEquipmentTypeResultRequestDto : PagedResultRequestDto
{ public string Code { get; set; } public string Name { get; set; } public bool? IsActive { get; set; } }
}

5. 建立实体类的功能接口(增删查改),并实现接口。

建立接口:因为ABP接口已经实现了基础功能(增删查改)的方法定义,所以直接继承IAsyncCrudAppService即可,写法参照已有的User相关类。

 using Abp.Application.Services;
using oMES_APServer.Companies.Dto; namespace oMES_APServer.Equipments
{
public interface IEquipmentTypesAppService : IAsyncCrudAppService<CompanyDto, int, PagedCompanyResultRequestDto, CompanyDto, CompanyDto>
{ }
}

自定义实现基础接口:

 using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using oMES_APServer.Equipments.Dto; namespace oMES_APServer.Equipments
{
public class EquipmentTypesAppService : AsyncCrudAppService<EquipmentType, EquipmentTypeDto, int, PagedEquipmentTypeResultRequestDto, EquipmentTypeDto, EquipmentTypeDto>, IEquipmentTypeAppService
{
private readonly IRepository<EquipmentType> _equipmentTypeRepository; public EquipmentTypesAppService(IRepository<EquipmentType> equipmentTypeRepository)
: base(equipmentTypeRepository)
{
_equipmentTypeRepository = equipmentTypeRepository; LocalizationSourceName = oMES_APServerConsts.LocalizationSourceName;
} public override async Task<EquipmentTypeDto> Get(EntityDto<int> input)
{
var equipmentType = await _equipmentTypeRepository
.GetAsync(input.Id); return ObjectMapper.Map<EquipmentTypeDto>(equipmentType);
} public override async Task<PagedResultDto<EquipmentTypeDto>> GetAll(PagedEquipmentTypeResultRequestDto input)
{
var equipmentTypes = Repository.GetAll()
.WhereIf(!input.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Name))
.WhereIf(!input.Code.IsNullOrWhiteSpace(), x => x.Code.Contains(input.Code))
.WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive)
.OrderBy(x => x.Code); return await Task.FromResult(new PagedResultDto<EquipmentTypeDto>(equipmentTypes.CountAsync().Result,
ObjectMapper.Map<List<EquipmentTypeDto>>(equipmentTypes)
));
} public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input)
{ //判断CODE是否已存在
var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model != null)
{
throw new UserFriendlyException(L("EquipmentType code already exists"));
} //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
} var entity = ObjectMapper.Map<EquipmentType>(input);
await _equipmentTypeRepository.InsertAsync(entity);
return MapToEntityDto(entity);
} public override async Task<EquipmentTypeDto> Update(EquipmentTypeDto input)
{
var entity = await _equipmentTypeRepository.GetAsync(input.Id); ObjectMapper.Map(input, entity); await _equipmentTypeRepository.UpdateAsync(entity); return MapToEntityDto(entity);
} public override async Task Delete(EntityDto<int> input)
{
var entity = await _equipmentTypeRepository.GetAsync(input.Id);
await _equipmentTypeRepository.DeleteAsync(entity);
} }
}

其中,创建的代码如下:在基类中,我们设置了Code字段为唯一键,所以需要先确定Code不存在

 public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input)
{ //判断CODE是否已存在
var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model != null)
{
throw new UserFriendlyException(L("EquipmentType code already exists"));
} //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
} var entity = ObjectMapper.Map<EquipmentType>(input);
await _equipmentTypeRepository.InsertAsync(entity);
return MapToEntityDto(entity);
}

ABP的全属性类FullAuditedEntity中,预置了软删除功能,如果一条数据被软删除了(IsDeleted字段为1),那么直接查找是招不到的。

需要临时关闭软删除的过滤器,才能找到:在using中,使用正常的查询代码,就能查到已被软删除的数据。

 //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
}

6. 添加视图模型ViewModel。

添加查询视图模型,这里没有做特殊处理,直接使用Dto

 using oMES_APServer.Equipments.Dto;
using System.Collections.Generic; namespace oMES_APServer.Web.Models.EquipmentTypes
{
public class EquipmentTypeListViewModel
{
public IReadOnlyList<EquipmentTypeDto> EquipmentTypes { get; set; }
}
}

添加编辑视图模型

 using oMES_APServer.Equipments.Dto;

 namespace oMES_APServer.Web.Models.EquipmentTypes
{
public class EditEquipmentTypeModalViewModel
{
public EquipmentTypeDto EquipmentType { get; set; }
}
}

7. 添加控制器。

控制器中添加两个方法Index和Edit.

 using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Microsoft.AspNetCore.Mvc;
using oMES_APServer.Controllers;
using oMES_APServer.Equipments;
using oMES_APServer.Equipments.Dto;
using oMES_APServer.Web.Models.EquipmentTypes; namespace oMES_APServer.Web.Mvc.Controllers
{
public class EquipmentTypesController : oMES_APServerControllerBase
{ private readonly IEquipmentTypeAppService _equipmentTypeAppService; public EquipmentTypesController(IEquipmentTypeAppService equipmentTypeAppService)
{
_equipmentTypeAppService = equipmentTypeAppService;
} public async Task<IActionResult> Index()
{
var modelDto = (await _equipmentTypeAppService
.GetAll(new PagedEquipmentTypeResultRequestDto { MaxResultCount = int.MaxValue })
).Items;
var viewModel = new EquipmentTypeListViewModel
{
EquipmentTypeList = modelDto
};
return View(viewModel);
} public async Task<ActionResult> EditEquipmentTypeModal(int id)
{
var modelDto = await _equipmentTypeAppService.Get(new EntityDto(id));
var editViewModel = new EditEquipmentTypeModalViewModel
{
EquipmentType = modelDto
};
return View("_EditEquipmentTypeModal", editViewModel);
} }
}

8. 添加视图。

视图由user中相关视图复制而来,将名称user更改为equipmentType相关即可使用。

查看&新建视图

 @using oMES_APServer.Web.Startup
@using oMES_APServer.Equipments
@model oMES_APServer.Web.Models.EquipmentTypes.EquipmentTypeListViewModel
@{
ViewBag.CurrentPageName = PageNames.EquipmentTypes;
}
@section scripts
{
<environment names="Development">
<script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script>
</environment> <environment names="Staging,Production">
<script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script>
</environment>
}
<div class="row clearfix">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="card">
<div class="header">
<h2>
@L("EquipmentType")
</h2>
<ul class="header-dropdown m-r--5">
<li class="dropdown">
<a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<i class="material-icons">more_vert</i>
</a>
<ul class="dropdown-menu pull-right">
<li><a id="RefreshButton" href="javascript:void(0);" class="waves-effect waves-block"><i class="material-icons">refresh</i>@L("Refresh")</a></li>
</ul>
</li>
</ul>
</div>
<div class="body table-responsive">
<table class="table">
<thead>
<tr>
<th>@L("Code")</th>
<th>@L("Name")</th>
<th>@L("BriefName")</th>
<th>@L("Remark")</th>
<th>@L("CreationTime")</th>
<th>@L("CreatorUserId")</th>
<th>@L("LastModificationTime")</th>
<th>@L("LastModifierUserId")</th>
</tr>
</thead>
<tbody>
@foreach (var viewModel in Model.EquipmentTypeList)
{
<tr>
<td>@viewModel.Code</td>
<td>@viewModel.Name</td>
<td>@viewModel.BriefName</td>
<td>@viewModel.Remark</td>
<td>@viewModel.CreationTime</td>
<td>@viewModel.CreatorUserId</td>
<td>@viewModel.LastModificationTime</td>
<td>@viewModel.LastModifierUserId</td> <td class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<i class="material-icons">menu</i>
</a>
<ul class="dropdown-menu pull-right">
<li><a href="#" class="waves-effect waves-block edit-equipmentType" data-equipmentType-id="@viewModel.Id" data-toggle="modal" data-target="#EquipmentTypeEditModal"><i class="material-icons">edit</i>@L("Edit")</a></li>
<li><a href="#" class="waves-effect waves-block delete-equipmentType" data-equipmentType-id="@viewModel.Id" data-equipmentType-name="@viewModel.Name"><i class="material-icons">delete_sweep</i>@L("Delete")</a></li>
</ul>
</td>
</tr>
}
</tbody>
</table>
<button type="button" class="btn btn-primary btn-circle waves-effect waves-circle waves-float pull-right" data-toggle="modal" data-target="#EquipmentTypeCreateModal">
<i class="material-icons">add</i>
</button>
</div>
</div>
</div>
</div> <div class="modal fade" id="EquipmentTypeCreateModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeCreateModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form name="equipmentTypeCreateForm" role="form" novalidate class="form-validation">
<div class="modal-header">
<h4 class="modal-title">
<span>@L("CreateNewEquipmentType")</span>
</h4>
</div>
<div class="modal-body">
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Code" required maxlength="@EquipmentType.MaxCodeLength">
<label class="form-label">@L("Code")</label>
</div>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Name" required maxlength="@EquipmentType.MaxNameLength">
<label class="form-label">@L("Name")</label>
</div>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="BriefName" maxlength="@EquipmentType.MaxBriefNameLength">
<label class="form-label">@L("BriefName")</label>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Remark" maxlength="@EquipmentType.MaxRemarkLength">
<label class="form-label">@L("Remark")</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 class="modal fade" id="EquipmentTypeEditModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeEditModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content"> </div>
</div>
</div>

编辑视图

 @using oMES_APServer.Web.Models.Common.Modals
@model oMES_APServer.Web.Models.EquipmentTypes.EditEquipmentTypeModalViewModel
@{
Layout = null;
}
@Html.Partial("~/Views/Shared/Modals/_ModalHeader.cshtml", new ModalHeaderViewModel(L("EditEquipmentType"))) <div class="modal-body">
<form name="EquipmentTypeEditForm" role="form" novalidate class="form-validation">
<input type="hidden" name="Id" value="@Model.EquipmentType.Id" />
<ul class="nav nav-tabs tab-nav-right" role="tablist">
<li role="presentation" class="active"><a href="#edit-equipmentType-details" data-toggle="tab">@L("EquipmentTypeDetails")</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane animated fadeIn active" id="edit-equipmentType-details"> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="code" type="text" name="Code" value="@Model.EquipmentType.Code" required maxlength="" minlength="" class="validate form-control">
<label for="code" class="form-label">@L("Code")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="name" type="text" name="Name" value="@Model.EquipmentType.Name" required maxlength="" minlength="" class="validate form-control">
<label for="name" class="form-label">@L("Name")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="briefname" type="text" name="BriefName" value="@Model.EquipmentType.BriefName" maxlength="" minlength="" class="validate form-control">
<label for="briefname" class="form-label">@L("BriefName")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="remark" type="text" name="Remark" value="@Model.EquipmentType.Remark" maxlength="" minlength="" class="validate form-control">
<label for="remark" class="form-label">@L("Remark")</label>
</div>
</div>
</div>
</div> </div>
</div>
</form>
</div> @Html.Partial("~/Views/Shared/Modals/_ModalFooterWithSaveAndCancel.cshtml") <script src="~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js" asp-append-version="true"></script>

9. 添加js脚本。

视图中添加了js脚本,此处添加合适的js脚本,此脚本由user.js复制而来,更改为equipmentType即可使用。

添加的位置如上述视图中代码所示:"~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js"

index.js如下

 (function () {
$(function () { var _equipmentTypeService = abp.services.app.equipmentType;
var _$modal = $('#EquipmentTypeCreateModal');
var _$form = _$modal.find('form'); _$form.validate(); $('#RefreshButton').click(function () {
refreshequipmentTypeList();
}); //删除方法
$('.delete-equipmentType').click(function () {
var equipmentTypeId = $(this).attr("data-equipmentType-id");
var tenancyName = $(this).attr('data-equipmentType-name'); deleteequipmentType(equipmentTypeId, tenancyName);
}); //编辑方法
$('.edit-equipmentType').click(function (e) {
var equipmentTypeId = $(this).attr("data-equipmentType-id"); e.preventDefault();
$.ajax({
url: abp.appPath + 'equipmentTypes/EditEquipmentTypeModal?equipmentTypeId=' + equipmentTypeId,
type: 'POST',
contentType: 'application/html',
success: function (content) {
$('#EquipmentTypeEditModal div.modal-content').html(content);
},
error: function (e) { }
});
}); _$form.find('button[type="submit"]').click(function (e) {
e.preventDefault(); if (!_$form.valid()) {
return;
} var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js abp.ui.setBusy(_$modal);
_equipmentTypeService.create(equipmentType).done(function () {
_$modal.modal('hide');
location.reload(true); //reload page to see new equipmentType!
}).always(function () {
abp.ui.clearBusy(_$modal);
});
}); _$modal.on('shown.bs.modal', function () {
_$modal.find('input:not([type=hidden]):first').focus();
}); function refreshequipmentTypeList() {
location.reload(true); //reload page to see new equipmentType!
} function deleteequipmentType(equipmentTypeId, equipmentTypeName) {
abp.message.confirm(
abp.utils.formatString(abp.localization.localize('AreYouSureWantToDelete', 'oMES_APServer'), equipmentTypeName),
function (isConfirmed) {
if (isConfirmed) {
_equipmentTypeService.delete({
id: equipmentTypeId
}).done(function () {
refreshequipmentTypeList();
});
}
}
);
}
});
})();

编辑模型的脚本_EditEquipmentTypeModal.js如下

 (function ($) {

     var _equipmentTypeService = abp.services.app.equipmentType;
var _$modal = $('#EquipmentTypeEditModal');
var _$form = $('form[name=EquipmentTypeEditForm]'); function save() { if (!_$form.valid()) {
return;
} var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js abp.ui.setBusy(_$form);
_equipmentTypeService.update(equipmentType).done(function () {
_$modal.modal('hide');
location.reload(true); //reload page to see edited equipmentType!
}).always(function () {
abp.ui.clearBusy(_$modal);
});
} //Handle save button click
_$form.closest('div.modal-content').find(".save-button").click(function (e) {
e.preventDefault();
save();
}); //Handle enter key
_$form.find('input').on('keypress', function (e) {
if (e.which === ) {
e.preventDefault();
save();
}
}); $.AdminBSB.input.activate(_$form); _$modal.on('shown.bs.modal', function () {
_$form.find('input[type=text]:first').focus();
});
})(jQuery);

10. 添加前端菜单(入口)。

菜单需在startup文件夹 xxxNavigationProvider类中,添加.AddItem代码。

.AddItem放置的顺序不同,界面中的显示顺序就不同。

 using Abp.Application.Navigation;
using Abp.Localization;
using oMES_APServer.Authorization; namespace oMES_APServer.Web.Startup
{
/// <summary>
/// This class defines menus for the application.
/// </summary>
public class oMES_APServerNavigationProvider : NavigationProvider
{
public override void SetNavigation(INavigationProviderContext context)
{
context.Manager.MainMenu
.AddItem(
new MenuItemDefinition(
PageNames.EquipmentTypes,
L("EquipmentTypes"),
url: "EquipmentTypes",
icon: "info"
)
)
以下省略
MenuItemDefinition的各参数看名字就能理解,从上到下依次是:
菜单名称,
菜单显示名称,
url:链接,即控制器名称
icon:图标名称,会根据名称自动查找对应的图标文件。

11. 添加权限管理。

通常的权限管理方式为:人员->角色->权限。

即为人员分配角色,为角色分配权限,这样就避免了多人相同权限时,重复分配的工作。

此处将设备管理功能(菜单)分配给对应的角色。

需要添加如下代码:

1、添加权限名称

 namespace oMES_APServer.Authorization
{
public static class PermissionNames
{
public const string Pages_Tenants = "Pages.Tenants";
public const string Pages_Users = "Pages.Users";
public const string Pages_Roles = "Pages.Roles";
//添加自定义权限名称
public const string Pages_Companies = "Pages.Companies";
public const string Pages_Departments = "Pages.Departments"; public const string Pages_EquipmentTypes = "Pages.EquipmentTypes";
}
}

2、系统权限列表中,添加该权限名称

 using Abp.Authorization;
using Abp.Localization;
using Abp.MultiTenancy; namespace oMES_APServer.Authorization
{
public class oMES_APServerAuthorizationProvider : AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host); //添加自定义权限
context.CreatePermission(PermissionNames.Pages_Companies, L("Companies"));
context.CreatePermission(PermissionNames.Pages_Departments, L("Departments"));
context.CreatePermission(PermissionNames.Pages_EquipmentTypes, L("EquipmentTypes"));
} private static ILocalizableString L(string name)
{
return new LocalizableString(name, oMES_APServerConsts.LocalizationSourceName);
}
}
}

3、菜单中添加权限控制

requiredPermissionName: PermissionNames.Pages_Companies

4、控制器中添加权限控制

[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]

5、应用服务方法中添加权限控制

[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]

添加完成后,运行程序,角色管理中,就可以单独选择该功能的权限了。

12. 文本翻译。

ABP的翻译方法在xxx.Core项目Localization文件夹中

默认支持9种语言。

添加中文翻译,只需在xxx-zh-Hans.xml文件中添加相应字段即可。

这要注意一下:xml中的子项,如果name值相同的话,会报错。所以每次添加新翻译时,先检查一下name值是否重复。

如下添加即可:

到此,一个基础资料的基础功能就完成了。

之后会继续完善所有的基础功能,中间有对ABP功能的研究也会一点一点写出来。

【ABP】从零开始学习ABP_001_新建实体功能的更多相关文章

  1. 【ABP】从零开始学习ABP_入门介绍

    本文介绍自己入坑ABP的过程,一些ABP的相关文章.QQ群,以及ABP Zero示例项目的运行. 背景 作为一个半路出家学习编程的新人,之前工作中也断断续续写过一些代码,但底层核心一直没机会学习,所以 ...

  2. ASP.NET从零开始学习EF的增删改查

           ASP.NET从零开始学习EF的增删改查           最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...

  3. Microsoft Dynamics CRM 2011 新建实体 需要注意的细节

    新建一个实体,需要红色框内的是否勾选的意义,可以进一步加深对CRM的理解.如图: 下面对部分的进行了自我的理解,不对的地方,还请大家指出来.互相学习. 1.CRM2011中,在活动方面加强的新特性包括 ...

  4. 从零开始学习CocoaPods安装和使用

    从零开始学习CocoaPods安装和使用   转载: Code4App原创:http://code4app.com/article/cocoapods-install-usage http://m.i ...

  5. ABP Framework V4.4 RC 新增功能介绍

    目录 新增功能概述 启动模板删除 EntityFrameworkCore.DbMigrations 项目 CMS-Kit 动态菜单管理 Razor引擎对文本模板的支持 DbContext/Entiti ...

  6. 结合ABP源码实现邮件发送功能

    1. 前言 2. 实现过程 1. 代码图(重) 2.具体实现 2.1 定义AppSettingNames及AppSettingProvider 2.2 EmailSenderConfiguration ...

  7. 从零开始学习jQuery (五) 事件与事件对象

    本系列文章导航 从零开始学习jQuery (五) 事件与事件对象 一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解 ...

  8. 从零开始学习jQuery (二) 万能的选择器

    本系列文章导航 从零开始学习jQuery (二) 万能的选择器 一.摘要 本章讲解jQuery最重要的选择器部分的知识. 有了jQuery的选择器我们几乎可以获取页面上任意的一个或一组对象, 可以明显 ...

  9. 从零开始学习jQuery (一) 入门篇

    本系列文章导航 从零开始学习jQuery (一) 入门篇 一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些 ...

随机推荐

  1. 「NOIP2013」货车运输

    传送门 Luogu 解题思路 首先 \(\text{Kruskal}\) 一下,构造出一棵森林. 并查集还要用来判断连通性. 倍增 \(\text{LCA}\) 的时候顺便维护一下路径最小值即可. 细 ...

  2. 使用URLConnection获取页面返回的xml数据

    public static void main(String[] args) throws Exception { String path="http://flash.weather.com ...

  3. 【SSM sql.xml】日志查询mapper.xml

    LogInfoMapper.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapp ...

  4. 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)

    题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...

  5. 添加COOKIE

    HttpCookie userinfoCookie = new HttpCookie("userinfo"); JObject o = new JObject();//JObjec ...

  6. 「JSOI2015」最大公约数

    「JSOI2015」最大公约数 传送门 考虑先枚举区间左端点, 然后我们会发现所有可能的区间虽然有 \(O(n)\) 个,但是本质不同的区间 \(\gcd\) 只有 \(\log n\) 级别,而且是 ...

  7. 转载--php函数使用--var_export

    var_export用于将数组转换成字符串 <?php $arr = [ 'key1'=>'val1', 'key2'=>'val2', 'key3'=>'val3', 'ke ...

  8. MySQL - 在Ubuntu下密码初始化

    1. 打开/etc/mysql/debian.cnf文件,在这个文件中有系统默认给我们分配的用户名和密码,通过这个密码就可以直接对MySQL进行操作了. 2. 以debian-sys-maint为用户 ...

  9. C++的const成员函数

    我们知道,在C++中,若一个变量声明为const类型,则试图修改该变量的值的操作都被视编译错误.例如, const char blank = ‘’; blank = ‘\n’;  // 错误 面向对象 ...

  10. Win10 在 CUDA 10.1 下跑 TensorFlow 2.x

    深度学习最热的两个框架是 pytorch 和 tensorflow,pytorch 最新版本是 1.3,tensorflow 最新版本为 2.0,在 win10 下 pytorch 1.3 要求的 c ...