I want to extend BasicRepositoryBase to add a new function for all my repositories.
I created my interface as follows
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);
}
}
I created my repository as follows. I added a new function CreateOrUpdate.
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);
}
}
To register new repository I tried two different approaches in ApplicationModule File
first approach
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<FMSApplicationModule>();
});
context.Services.AddScoped(typeof(IFMSRepository<,>), typeof(FMSRepository<,>));
}
Second approach
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);
});
}
Both option yield the same error in my data seeder class which I use the new repository method. Below is my data seeder class
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
}
) ;
}
}
}
}
Here is the DataSeeder program output.
[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.
---> 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.<>c__DisplayClass14_0.<UseSingleConstructorActivation>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.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass41_0.<PropertiesAutowired>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.<>c__DisplayClass14_0.<BuildPipeline>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.<>c__DisplayClass14_0.<BuildPipeline>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.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>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& 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.<Main>(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...^A
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
[Process completed]
Any help is appreciated.
You are trying to register an abstract class, instead you need to register a concrete class. You can inherit from the EfCoreRepository
class. Or in an easier way, you can write it as an extensions method.