ABP框架实现组织单元切换功能的技术解析

ABP框架实现组织单元切换功能的技术解析

abp Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation. abp 项目地址: https://gitcode.com/gh_mirrors/abp1/abp

引言

在企业级应用开发中,多组织架构管理是一个常见需求。ABP框架提供了一套完整的解决方案,帮助开发者轻松实现组织单元切换功能。本文将详细介绍如何在ABP框架中实现这一功能,包括数据过滤、组织单元管理、用户界面集成等核心环节。

核心概念

组织单元(Organization Unit)

组织单元是企业架构中的基本单位,代表公司内部的部门、分支机构等。在ABP框架中,组织单元通过OrganizationUnit实体进行管理,用户可以属于多个组织单元。

数据过滤机制

ABP框架提供了强大的数据过滤功能,允许开发者基于特定条件自动过滤数据。在本场景中,我们将基于当前选择的组织单元ID来过滤数据。

实现步骤

1. 定义数据过滤接口

首先创建一个IHasOrganization接口,用于标记需要按组织单元过滤的实体:

public interface IHasOrganization
{
    public Guid? OrganizationId { get; set; }
}

2. 实体类实现

让需要按组织单元过滤的实体实现该接口:

public class Book : AggregateRoot<Guid>, IHasOrganization
{
    public string Name { get; set; }
    public string Isbn { get; set; }
    public Guid? OrganizationId { get; set; }
}

3. 配置DbContext

在DbContext中配置数据过滤器:

public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
    // 其他配置...
    
    protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
    {
        if (typeof(IHasOrganization).IsAssignableFrom(typeof(TEntity)))
        {
            return true;
        }
        return base.ShouldFilterEntity<TEntity>(entityType);
    }

    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
    {
        var expression = base.CreateFilterExpression<TEntity>(modelBuilder);

        if (typeof(IHasOrganization).IsAssignableFrom(typeof(TEntity)))
        {
            Expression<Func<TEntity, bool>> hasOrganizationIdFilter = 
                e => EF.Property<Guid>(e, "OrganizationId") == CurrentOrganizationIdProvider.CurrentOrganizationId;
            expression = expression == null ? hasOrganizationIdFilter : 
                QueryFilterExpressionHelper.CombineExpressions(expression, hasOrganizationIdFilter);
        }

        return expression;
    }
}

4. 实现当前组织单元提供者

创建一个单例服务来管理当前组织单元ID:

public class CurrentOrganizationIdProvider : ISingletonDependency
{
    private readonly AsyncLocal<Guid?> _currentOrganizationId = new AsyncLocal<Guid?>();

    public Guid? CurrentOrganizationId => _currentOrganizationId.Value;

    public virtual IDisposable Change(Guid? organizationId)
    {
        var parent = CurrentOrganizationId;
        _currentOrganizationId.Value = organizationId;
        return new DisposeAction(() => _currentOrganizationId.Value = parent);
    }
}

5. 浏览器信息管理

为了支持多标签页不同组织单元选择,需要添加浏览器信息识别:

public class BrowserInfoClaimsPrincipalContributor : IAbpClaimsPrincipalContributor
{
    public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
    {
        var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
        identity?.AddClaim(new Claim("BrowserInfo", Guid.NewGuid().ToString()));
        return Task.CompletedTask;
    }
}

6. 应用服务实现

创建组织单元管理应用服务:

[Authorize]
public class CurrentOrganizationAppService : BookStoreAppService
{
    public virtual async Task<List<OrganizationDto>> GetOrganizationListAsync()
    {
        // 获取用户所属组织单元列表
    }

    public virtual async Task<Guid?> GetCurrentOrganizationIdAsync()
    {
        // 获取当前选择的组织单元ID
    }

    public virtual async Task ChangeAsync(Guid? organizationId)
    {
        // 更改当前组织单元ID
    }
}

7. 数据种子

添加示例数据:

public class BooksDataSeedContributor : IDataSeedContributor
{
    public virtual async Task SeedAsync(DataSeedContext context)
    {
        // 创建组织单元
        await _organizationUnitManager.CreateAsync(new OrganizationUnit(UsaBranchId, "USA Branch"));
        await _organizationUnitManager.CreateAsync(new OrganizationUnit(TurkeyBranchId, "Turkey Branch"));
        
        // 添加用户到组织单元
        await _identityUserManager.AddToOrganizationUnitAsync(admin.Id, UsaBranchId);
        await _identityUserManager.AddToOrganizationUnitAsync(admin.Id, TurkeyBranchId);
        
        // 添加示例书籍
        await _bookRepository.InsertAsync(new Book
        {
            Name = "1984",
            Isbn = "978-0451524935",
            OrganizationId = UsaBranchId
        });
        // 更多书籍...
    }
}

8. 用户界面集成

创建组织单元切换组件:

<div class="dropstart">
    <a href="#" class="btn mt-2" data-bs-toggle="dropdown">
        <i class="fa fa-city m-auto"></i>
    </a>
    <ul class="dropdown-menu p-0" style="width: 200px">
        <div class="list-group">
            @foreach (var ou in Model.OrganizationDtos)
            {
                <button type="button" onclick="setOrganizationUnitId('@ou.Id')" 
                    class="list-group-item list-group-item-action @(ou.Id == Model.CurrentOrganizationId ? "active" : "")">
                    @ou.DisplayName
                </button>
            }
        </div>
    </ul>
</div>

9. 中间件配置

添加中间件在请求管道中设置当前组织单元:

app.UseAuthorization();
app.Use(async (httpContext, next) =>
{
    // 从缓存获取当前组织单元ID并设置
    var currentUser = httpContext.RequestServices.GetRequiredService<ICurrentUser>();
    var cacheKey = currentUser.Id + ":" + currentUser.GetBrowserInfo();
    var cacheItem = await cache.GetAsync(cacheKey);
    
    if (cacheItem != null)
    {
        var provider = httpContext.RequestServices.GetRequiredService<CurrentOrganizationIdProvider>();
        provider.Change(cacheItem.OrganizationId);
    }
    
    await next(httpContext);
});

性能优化

从ABP 8.3版本开始,框架引入了用户定义函数映射(User-defined function mapping)功能来优化全局过滤器的性能。这项技术通过将过滤逻辑下推到数据库层面执行,减少了内存中的数据操作,显著提高了查询效率。

总结

通过ABP框架实现组织单元切换功能,开发者可以:

  1. 轻松管理多组织架构
  2. 实现基于组织单元的数据隔离
  3. 提供灵活的用户界面交互
  4. 确保系统性能和可扩展性

这种实现方式不仅适用于简单的组织单元切换场景,也可以扩展为更复杂的多租户或多分支机构管理系统。ABP框架提供的强大基础设施大大降低了这类功能的开发难度,让开发者可以专注于业务逻辑的实现。

abp Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation. abp 项目地址: https://gitcode.com/gh_mirrors/abp1/abp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咎丹娜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值