Skip to content
Promote Your Product

Create Module API

1. Create Module Entity Class

Create a Module directory under MyCompanyName.MyProjectName.Api.Contracts\Domain, and create an entity class ModuleEntity in the Module directory.

cs
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using MyCompanyName.MyProjectName.Api.Contracts.Core.Consts;

namespace MyCompanyName.MyProjectName.Api.Contracts.Domain.Module;

/// <summary>
/// Module
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "module")]
[Index("idx_{tablename}_01", nameof(TenantId) + "," + nameof(Name), true)]
public partial class ModuleEntity : EntityTenant
{
    /// <summary>
    /// Name
    /// </summary>
    [Column(StringLength = 50)]
    public string Name { get; set; }
}

Convention: Entity classes are suffixed with Entity. Module can be replaced with the actual business module name. Table names and indexes use snake_case naming. Table name prefix starts with DbConsts.TableNamePrefix, and indexes start with idx.

After inheriting EntityTenant, queries will filter data based on the TenantId.

2. Create Input/Output DTOs

Create Input or Output directories under MyCompanyName.MyProjectName.Api.Contracts\Services

Create the add input DTO ModuleAddInput in the Input directory:

cs
namespace MyCompanyName.MyProjectName.Api.Contracts.Services.Module.Input;

/// <summary>
/// Add
/// </summary>
public class ModuleAddInput
{
    /// <summary>
    /// Name
    /// </summary>
    public string Name { get; set; }
}

Create the update input DTO ModuleUpdateInput in the Input directory:

cs
using System.ComponentModel.DataAnnotations;
using ZhonTai.Admin.Core.Validators;

namespace MyCompanyName.MyProjectName.Api.Contracts.Services.Module.Input;

/// <summary>
/// Update module
/// </summary>
public partial class ModuleUpdateInput : ModuleAddInput
{
    /// <summary>
    /// ID
    /// </summary>
    [Required]
    [ValidateRequired("Please select a module")]
    public long Id { get; set; }
}

Create the page input DTO ModuleGetPageInput in the Input directory:

cs
namespace MyCompanyName.MyProjectName.Api.Contracts.Services.Module.Input;

/// <summary>
/// Module page request
/// </summary>
public partial class ModuleGetPageInput
{
    /// <summary>
    /// Name
    /// </summary>
    public string Name { get; set; }
}

Create the single module output DTO ModuleGetOutput in the Output directory:

cs
using MyCompanyName.MyProjectName.Api.Contracts.Services.Module.Input;

namespace MyCompanyName.MyProjectName.Api.Services.Module.Output;

/// <summary>
/// Module response
/// </summary>
public class ModuleGetOutput : ModuleUpdateInput
{
}

Create the module page output DTO ModuleGetPageOutput in the Output directory:

cs
namespace MyCompanyName.MyProjectName.Api.Contracts.Services.Module.Output;

/// <summary>
/// Module page response
/// </summary>
public class ModuleGetPageOutput
{
    /// <summary>
    /// Primary key
    /// </summary>
    public long Id { get; set; }

    /// <summary>
    /// Name
    /// </summary>
    public string Name { get; set; }
}

3. Create Module API

Create a Module directory under MyCompanyName.MyProjectName.Api\Services, and create a module service ModuleService in the Module directory.

How service methods generate dynamic APIs: Add the [DynamicApi(Area = ApiConsts.AreaName)] attribute to the ModuleService and inherit the IDynamicApi interface.

Note

When developing with the project template, use AppRepositoryBase to create entity repositories. When developing with Admin.Core source code, use AdminRepositoryBase to create entity repositories.

cs
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Dto;
using ZhonTai.Admin.Services;
using MyCompanyName.MyProjectName.Api.Domain.Module;
using MyCompanyName.MyProjectName.Api.Domain.Module.Dto;
using MyCompanyName.MyProjectName.Api.Services.Module.Input;
using MyCompanyName.MyProjectName.Api.Services.Module.Output;
using MyCompanyName.MyProjectName.Api.Core.Consts;
using Newtonsoft.Json;
using ZhonTai;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;
using Microsoft.AspNetCore.Mvc;
using FreeScheduler;

namespace MyCompanyName.MyProjectName.Api.Services.Module;

/// <summary>
/// Module service
/// </summary>
[DynamicApi(Area = ApiConsts.AreaName)]
public class ModuleService : BaseService, IDynamicApi
{
    private readonly AppRepositoryBase<ModuleEntity> _moduleRep;

    public ModuleService(AppRepositoryBase<ModuleEntity> moduleRep)
    {
        _moduleRep = moduleRep;
    }

    /// <summary>
    /// Get module
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<ModuleGetOutput> GetAsync(long id)
    {
        var result = await _moduleRep.GetAsync<ModuleGetOutput>(id);
        return result;
    }

    /// <summary>
    /// Get page
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<PageOutput<ModuleGetPageOutput>> GetPageAsync(PageInput<ModuleGetPageInput> input)
    {
        var key = input.Filter?.Name;

        var list = await _moduleRep.Select
        .WhereIf(key.NotNull(), a => a.Name.Contains(key))
        .Count(out var total)
        .OrderByDescending(true, c => c.Id)
        .Page(input.CurrentPage, input.PageSize)
        .ToListAsync<ModuleGetPageOutput>();

        var data = new PageOutput<ModuleGetPageOutput>()
        {
            List = list,
            Total = total
        };

        return data;
    }

    /// <summary>
    /// Add
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<long> AddAsync(ModuleAddInput input)
    {
        var entity = Mapper.Map<ModuleEntity>(input);
        await _moduleRep.InsertAsync(entity);

        return entity.Id;
    }

    /// <summary>
    /// Update
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task UpdateAsync(ModuleUpdateInput input)
    {
        var entity = await _moduleRep.GetAsync(input.Id);
        if (!(entity?.Id > 0))
        {
            throw ResultOutput.Exception("Module does not exist");
        }

        Mapper.Map(input, entity);
        await _moduleRep.UpdateAsync(entity);
    }

    /// <summary>
    /// Hard delete
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task DeleteAsync(long id)
    {
        await _moduleRep.DeleteAsync(m => m.Id == id);
    }

    /// <summary>
    /// Soft delete
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task SoftDeleteAsync(long id)
    {
        await _moduleRep.SoftDeleteAsync(id);
    }

    /// <summary>
    /// Batch soft delete
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public async Task BatchSoftDeleteAsync(long[] ids)
    {
        await _moduleRep.SoftDeleteAsync(ids);
    }
}

API Permission Description

  • [Login] marks that the user must be logged in to access the API. This attribute is convenient for testing unauthorized APIs.
cs
[Login]
public async Task<ModuleGetOutput> GetAsync(long id)
{
    var result = await _moduleRepository.GetAsync<ModuleGetOutput>(id);
    return result;
}
  • [AllowAnonymous] marks that the user can access the API anonymously. This attribute is convenient for testing APIs that are both unauthorized and unauthenticated.
cs
[AllowAnonymous]
public async Task<ModuleGetOutput> GetAsync(long id)
{
    var result = await _moduleRepository.GetAsync<ModuleGetOutput>(id);
    return result;
}

Note

For authorized APIs, remove the [Login] and [AllowAnonymous] attributes.