You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ABP框架扩展BasicRepositoryBase添通用仓储方法遇依赖注入错误

问题:ABP框架扩展仓储后依赖注入失败

我在ABP框架中扩展BasicRepositoryBase,为所有自定义仓储添加通用CreateOrUpdate方法,完成以下操作后,在数据种子类中依赖注入IFMSRepository<FairArea, Guid>时触发Autofac依赖解析异常,提示无法解析该参数、无法构造目标类:

  • 定义泛型接口IFMSRepository<TEntity, TKey>,继承IBasicRepository和IRepository,新增CreateOrUpdate方法
  • 实现抽象基类FMSRepository<TEntity,TKey>,继承BasicRepositoryBase并实现IFMSRepository接口,完成CreateOrUpdate逻辑,同时声明多个抽象方法
  • 在ApplicationModule中尝试两种服务注册方式:直接注册泛型接口与实现类、反射扫描注册

相关代码

1. IFMSRepository接口代码

using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;

namespace FMS.Domain.Repositories
{
    public interface IFMSRepository<TEntity, TKey> : IBasicRepository<TEntity,TKey>, IRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>
    {
        Task<TEntity> CreateOrUpdate(TEntity entity);
    }
}

2. FMSRepository抽象基类代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

namespace FMS.Domain.Repositories
{
    public abstract class FMSRepository<TEntity, TKey> : BasicRepositoryBase<TEntity, TKey>, IFMSRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>
    {
        
        public async Task<TEntity> CreateOrUpdate(TEntity entity )
        {
            TEntity resultEntity;

            if (entity.Id == null)
            {
                resultEntity = await InsertAsync(entity);
            }
            else
            {
                var checkEntity = await GetAsync(entity.Id);

                if (checkEntity != null)
                    resultEntity = await UpdateAsync(entity);
                else
                    resultEntity = await InsertAsync(entity);
            }

            return resultEntity;
        }

        public abstract Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default);
        public abstract Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
        public abstract Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default);
        public abstract Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default);
        public abstract Task<IQueryable<TEntity>> GetQueryableAsync();
        public abstract IQueryable<TEntity> WithDetails();
        public abstract IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors);
        public abstract Task<IQueryable<TEntity>> WithDetailsAsync();
        public abstract Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors);
    }
}

3. 服务注册方式1:直接注册泛型

public override void ConfigureServices(ServiceConfigurationContext context)
{
    Configure<AbpAutoMapperOptions>(options =>
    {
        options.AddMaps<FMSApplicationModule>();
    });

    context.Services.AddScoped(typeof(IFMSRepository<,>), typeof(FMSRepository<,>));
}

4. 服务注册方式2:反射扫描注册

public override void ConfigureServices(ServiceConfigurationContext context)
{
    Configure<AbpAutoMapperOptions>(options =>
    {
        options.AddMaps<FMSApplicationModule>();
    });
    
    System.Reflection.Assembly.GetExecutingAssembly()
        .GetTypes()
        .Where(item => item.GetInterfaces()
        .Where(i => i.IsGenericType).Any(i => i.GetGenericTypeDefinition() == typeof(IFMSRepository<,>)) && !item.IsAbstract && !item.IsInterface)
        .ToList()
        .ForEach(assignedTypes =>
        {
            var serviceType = assignedTypes.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof(IFMSRepository<,>));
            context.Services.AddScoped(serviceType, assignedTypes);
        });
}

5. 数据种子类代码

using System;
using System.Threading.Tasks;
using FMS.Domain.Repositories;
using FMS.Fairs;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;

namespace FMS.DataSeed
{
    public class FMSDataSeederContributer
    : IDataSeedContributor, ITransientDependency
    {
        private readonly IFMSRepository<FairArea, Guid> _fairAreaRepository;
        private readonly ICurrentTenant _currentTenant;

        public FMSDataSeederContributer(
            IFMSRepository<FairArea,Guid> fairAreaRepository,
            ICurrentTenant currentTenant)
        {
            _fairAreaRepository = fairAreaRepository;
            _currentTenant = currentTenant;
        }

        public async Task SeedAsync(DataSeedContext context)
        {
            using (_currentTenant.Change(context?.TenantId))
            {
                if (context?.TenantId == null)
                {
                    return;
                }
                if (await _fairAreaRepository.GetCountAsync() > 0)
                {
                    return;
                }
                await _fairAreaRepository.CreateOrUpdate(
                    new FairArea
                    {
                        Name = "Name of Area",
                        Type = FairAreaType.ClosedArea,
                        Description = "Description of Area",
                        Address = "Country of Area",
                        TenantId = _currentTenant.Id
                    }
                );
            }
        }
    }
}

错误日志

[23:12:10 INF] Started database migrations...[23:12:10 INF] Migrating schema for host database...[23:12:11 INF] Executing host database seed...Unhandled exception. Autofac.Core.DependencyResolutionException: An exception was thrown while activating FMS.DataSeed.FMSDataSeederContributer. ---&gt; Autofac.Core.DependencyResolutionException: None of the constructors found on type 'FMS.DataSeed.FMSDataSeederContributer' can be invoked with the available services and parameters:Cannot resolve parameter 'FMS.Domain.Repositories.IFMSRepository`2[FMS.Fairs.FairArea,System.Guid] fairAreaRepository' of constructor 'Void .ctor(FMS.Domain.Repositories.IFMSRepository`2[FMS.Fairs.FairArea,System.Guid], Volo.Abp.MultiTenancy.ICurrentTenant)'.
See https://autofac.rtfd.io/help/no-constructors-bindable for more info.   at Autofac.Core.Activators.Reflection.ReflectionActivator.&lt;&gt;c__DisplayClass14_0.&lt;UseSingleConstructorActivation&gt;b__0(ResolveRequestContext ctxt, Action`1 next)   at Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Builder.RegistrationBuilder`3.&lt;&gt;c__DisplayClass41_0.&lt;PropertiesAutowired&gt;b__0(ResolveRequestContext ctxt, Action`1 next)   at Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)   --- End of inner exception stack trace ---   at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)   at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext ctxt)   at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)   at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request)   at Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest request)   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest request)   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object&amp; instance)   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType)   at Autofac.Extensions.DependencyInjection.AutofacServiceProvider.GetRequiredService(Type serviceType)   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)   at Volo.Abp.Data.DataSeeder.SeedAsync(DataSeedContext context)   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)   at FMS.Data.FMSDbMigrationService.SeedDataAsync(Tenant tenant) in /Users/serhatonal/Documents/Codes/FMS/FMS/src/FMS.Domain/Data/FMSDbMigrationService.cs:line 103   at FMS.Data.FMSDbMigrationService.MigrateAsync() in /Users/serhatonal/Documents/Codes/FMS/FMS/src/FMS.Domain/Data/FMSDbMigrationService.cs:line 53   at FMS.DbMigrator.DbMigratorHostedService.StartAsync(CancellationToken cancellationToken) in /Users/serhatonal/Documents/Codes/FMS/FMS/src/FMS.DbMigrator/DbMigratorHostedService.cs:line 36   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)   at FMS.DbMigrator.Program.Main(String[] args) in /Users/serhatonal/Documents/Codes/FMS/FMS/src/FMS.DbMigrator/Program.cs:line 30   at FMS.DbMigrator.Program.&lt;Main&gt;(String[] args)bash: line 1: 28828 Abort trap: 6           "/usr/local/share/dotnet/dotnet" "/Users/serhatonal/Documents/Codes/FMS/FMS/src/FMS.DbMigrator/bin/Debug/net7.0/FMS.DbMigrator.dll"
Press any key to continue...^ASaving session......copying shared history......saving history...truncating history files......completed.
[Process completed]

问题原因与解决方案

核心原因

  1. FMSRepository<TEntity,TKey>是抽象类,Autofac无法实例化抽象类,直接注册泛型接口到抽象类的方式无效
  2. 反射扫描注册代码只查找非抽象的仓储实现类,但你没有为FairArea编写具体的仓储实现类,因此没有对应的服务注册项

解决步骤

1. 为具体实体编写仓储实现类

以FairArea为例,创建继承FMSRepository<FairArea, Guid>的具体仓储类,实现所有抽象方法(若使用EF Core,建议继承EfCoreRepositoryBase而非直接继承BasicRepositoryBase):

using FMS.Fairs;
using System;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace FMS.Domain.Repositories
{
    public class FairAreaRepository : FMSRepository<FairArea, Guid>, IFMSRepository<FairArea, Guid>
    {
        public FairAreaRepository(IDbContextProvider<FMSDbContext> dbContextProvider) 
            : base(dbContextProvider)
        {
        }

        // 直接调用基类方法实现所有抽象接口
        public override Task DeleteAsync(Expression<Func<FairArea, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            return base.DeleteAsync(predicate, autoSave, cancellationToken);
        }

        public override Task DeleteDirectAsync(Expression<Func<FairArea, bool>> predicate, CancellationToken cancellationToken = default)
        {
            return base.DeleteDirectAsync(predicate, cancellationToken);
        }

        public override Task<FairArea> FindAsync(Expression<Func<FairArea, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            return base.FindAsync(predicate, includeDetails, cancellationToken);
        }

        public override Task<FairArea> GetAsync(Expression<Func<FairArea, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            return base.GetAsync(predicate, includeDetails, cancellationToken);
        }

        public override Task<IQueryable<FairArea>> GetQueryableAsync()
        {
            return base.GetQueryableAsync();
        }

        public override IQueryable<FairArea> WithDetails()
        {
            return base.WithDetails();
        }

        public override IQueryable<FairArea> WithDetails(params Expression<Func<FairArea, object>>[] propertySelectors)
        {
            return base.WithDetails(propertySelectors);
        }

        public override Task<IQueryable<FairArea>> WithDetailsAsync()
        {
            return base.WithDetailsAsync();
        }

        public override Task<IQueryable<FairArea>> WithDetailsAsync(params Expression<Func<FairArea, object>>[] propertySelectors)
        {
            return base.WithDetailsAsync(propertySelectors);
        }
    }
}

2. 调整服务注册

两种可选方式:

  • 手动注册具体仓储:在ApplicationModule的ConfigureServices中添加
    context.Services.AddScoped<IFMSRepository<FairArea, Guid>, FairAreaRepository>();
    
  • 自动扫描注册:保留原反射扫描代码,现在会自动找到非抽象的FairAreaRepository并完成注册,无需手动逐个添加

3. 优化CreateOrUpdate方法

原方法中entity.Id == null的判断仅适用于可空主键,对于Guid这类非空值类型主键,新实体Id通常为默认值(Guid.Empty),建议改用ABP内置方法判断实体状态:

public async Task<TEntity> CreateOrUpdate(TEntity entity )
{
    if (EntityHelper.IsTransient(entity)) // 兼容所有主键
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:16:21