@gterdem
Our solution structure is bit different as compared to your microservice template. This application was create way before abp.io Micro service template came into picture. We connected with abp.io at times of creation of our application, it was created manually by guidance of abp.io support team only.
Can we please connect and have a look yourself as giving you sample source is not possible and we cannot provide you original source code as well.
Hi,
Could you please reply to this question ?
LitmusAppService
is not like any other app service
It is the custom base AppService
which Inherit from ApplicationService
And yes I am sure I am getting the same error.
Can you share the code?
LitmusAppService :
public abstract class LitmusAppService : ApplicationService
{
protected LitmusAppService()
{
LocalizationResource = typeof(LitmusResource);
}
}
CustomTenantAppService :
namespace SCV.Litmus.LitmusTenants
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITenantAppService), typeof(CustomTenantAppService))]
public class CustomTenantAppService : LitmusAppService, ITenantAppService
{
protected IEditionRepository EditionRepository { get; }
protected IDataSeeder DataSeeder { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
private readonly ISharedAppServices _sharedAppServices;
protected AbpDbConnectionOptions DbConnectionOptions { get; }
public CustomTenantAppService(
ITenantRepository tenantRepository,
IEditionRepository editionRepository,
ITenantManager tenantManager,
IDataSeeder dataSeeder,
IDistributedEventBus distributedEventBus,
IOptions<AbpDbConnectionOptions> dbConnectionOptions,
SCV.Litmus.SharedAppService.ISharedAppServices sharedAppServices)
{
EditionRepository = editionRepository;
DataSeeder = dataSeeder;
DistributedEventBus = distributedEventBus;
DbConnectionOptions = dbConnectionOptions.Value;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
_sharedAppServices = sharedAppServices;
}
}
}
Error :
[11:54:00 ERR] [null] The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Thanks @maliming It is working as expected you can close this ticket now.
I just have one query if you can answer that before you close this ticket.
This is my LitmusAppService
public abstract class LitmusAppService : ApplicationService
{
protected LitmusAppService()
{
LocalizationResource = typeof(LitmusResource);
}
}
I tried by inheriting LitmusAppService
still it gave me the same error
But LitmusAppService
inherits from ApplicationService
, this is one and the same right ?
I mean I am still not getting it why it is not working when I inherit it from LitmusAppServie
and why it is working when I inherit it from ApplicationService
.
You should use
ITenantAppService
in the controller instead ofCustomTenantAppService
So you mean I should override Controller also ? Can you provide some sample code ? See I just have to play around with ApplyDatabaseMigrationAsync only, I dont need to override the whole service. Give me some sample code how I can override or make new service and implement this method in it. And it should be called from Saas Tenants options on UI as below
I tried this as well, getting same issue as below
[11:54:00 ERR] [null] The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Hey Hi,
I was trying to refactor some code and lost my previous changes for my CustomTenantAppService. I tried rewriting it as below
CustomAppService:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Uow;
using Volo.Saas.Editions;
using Volo.Saas.Host;
using Volo.Saas.Host.Dtos;
using Volo.Saas.Tenants;
namespace SCV.Litmus.LitmusTenants
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITenantAppService))]
public class CustomTenantAppService : ITenantAppService
{
protected IEditionRepository EditionRepository { get; }
protected IDataSeeder DataSeeder { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
protected AbpDbConnectionOptions DbConnectionOptions { get; }
public CustomTenantAppService(
ITenantRepository tenantRepository,
IEditionRepository editionRepository,
ITenantManager tenantManager,
IDataSeeder dataSeeder,
IDistributedEventBus distributedEventBus,
IOptions<AbpDbConnectionOptions> dbConnectionOptions)
{
EditionRepository = editionRepository;
DataSeeder = dataSeeder;
DistributedEventBus = distributedEventBus;
DbConnectionOptions = dbConnectionOptions.Value;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
}
public virtual async Task<SaasTenantDto> GetAsync(Guid id)
{
var tenant = ObjectMapper.Map<Tenant, SaasTenantDto>(
await TenantRepository.GetAsync(id)
);
if (tenant.EditionId.HasValue)
{
var edition = await EditionRepository.GetAsync(tenant.EditionId.Value);
tenant.EditionName = edition.DisplayName;
}
return tenant;
}
public virtual async Task<PagedResultDto<SaasTenantDto>> GetListAsync(GetTenantsInput input)
{
var count = await TenantRepository.GetCountAsync(input.Filter);
var list = await TenantRepository.GetListAsync(
input.Sorting,
input.MaxResultCount,
input.SkipCount,
input.Filter,
includeDetails: true
);
var tenantDtos = ObjectMapper.Map<List<Tenant>, List<SaasTenantDto>>(list);
if (input.GetEditionNames)
{
var editions = await EditionRepository.GetListAsync();
foreach (var tenant in tenantDtos)
{
var edition = editions.FirstOrDefault(e => e.Id == tenant.EditionId);
tenant.EditionName = edition?.DisplayName;
}
}
return new PagedResultDto<SaasTenantDto>(
count,
tenantDtos
);
}
[Authorize(SaasHostPermissions.Tenants.Create)]
public virtual async Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
{
Tenant tenant = null;
async Task CreateTenantAsync()
{
tenant = await TenantManager.CreateAsync(input.Name, input.EditionId);
if (!input.DefaultConnectionString.IsNullOrWhiteSpace())
{
tenant.SetDefaultConnectionString(input.DefaultConnectionString);
}
input.MapExtraPropertiesTo(tenant);
/* Auto saving to ensure TenantCreatedEto handler can get the tenant! */
await TenantRepository.InsertAsync(tenant, autoSave: true);
}
if (input.DefaultConnectionString.IsNullOrWhiteSpace())
{
/* Creating the tenant in the current UOW */
await CreateTenantAsync();
}
else
{
/* Creating the tenant in a separate UOW to ensure it is created
* before creating the database.
* TODO: We should remove inner UOW once https://github.com/abpframework/abp/issues/6126 is done
*/
using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
{
await CreateTenantAsync();
await uow.CompleteAsync();
}
}
await DistributedEventBus.PublishAsync(
new TenantCreatedEto
{
Id = tenant.Id,
Name = tenant.Name,
Properties =
{
{"AdminEmail", input.AdminEmailAddress},
{"AdminPassword", input.AdminPassword}
}
}
);
return ObjectMapper.Map<Tenant, SaasTenantDto>(tenant);
}
[Authorize(SaasHostPermissions.Tenants.Update)]
public virtual async Task<SaasTenantDto> UpdateAsync(Guid id, SaasTenantUpdateDto input)
{
var tenant = await TenantRepository.GetAsync(id);
tenant.EditionId = input.EditionId;
await TenantManager.ChangeNameAsync(tenant, input.Name);
input.MapExtraPropertiesTo(tenant);
await TenantRepository.UpdateAsync(tenant);
return ObjectMapper.Map<Tenant, SaasTenantDto>(tenant);
}
[Authorize(SaasHostPermissions.Tenants.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
var tenant = await TenantRepository.FindAsync(id);
if (tenant == null)
{
return;
}
await TenantRepository.DeleteAsync(tenant);
}
[Authorize(SaasHostPermissions.Tenants.ManageConnectionStrings)]
public virtual async Task<string> GetDefaultConnectionStringAsync(Guid id)
{
var tenant = await TenantRepository.GetAsync(id);
return tenant.FindDefaultConnectionString();
}
[Authorize(SaasHostPermissions.Tenants.ManageConnectionStrings)]
public virtual async Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString)
{
Tenant tenant;
string oldValue;
using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
{
tenant = await TenantRepository.GetAsync(id);
oldValue = tenant.FindDefaultConnectionString();
if (oldValue == defaultConnectionString)
{
return;
}
tenant.SetDefaultConnectionString(defaultConnectionString);
await TenantRepository.UpdateAsync(tenant);
await uow.CompleteAsync();
}
await DistributedEventBus.PublishAsync(
new TenantConnectionStringUpdatedEto
{
Id = tenant.Id,
Name = tenant.Name,
ConnectionStringName = Volo.Abp.Data.ConnectionStrings.DefaultConnectionStringName,
OldValue = oldValue,
NewValue = defaultConnectionString
}
);
}
[Authorize(SaasHostPermissions.Tenants.ManageConnectionStrings)]
public virtual async Task DeleteDefaultConnectionStringAsync(Guid id)
{
Tenant tenant;
string oldValue;
using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
{
tenant = await TenantRepository.GetAsync(id);
oldValue = tenant.FindDefaultConnectionString();
if (oldValue == null)
{
return;
}
tenant.RemoveDefaultConnectionString();
await TenantRepository.UpdateAsync(tenant);
await uow.CompleteAsync();
}
await DistributedEventBus.PublishAsync(
new TenantConnectionStringUpdatedEto
{
Id = tenant.Id,
Name = tenant.Name,
ConnectionStringName = Volo.Abp.Data.ConnectionStrings.DefaultConnectionStringName,
OldValue = oldValue,
NewValue = null
}
);
}
[Authorize(SaasHostPermissions.Tenants.ManageConnectionStrings)]
public async Task ApplyDatabaseMigrationsAsync(Guid id)
{
await DistributedEventBus.PublishAsync(
new ApplyDatabaseMigrationsEto
{
TenantId = id,
DatabaseName = ConnectionStrings.DefaultConnectionStringName
}
);
foreach (var databaseInfo in DbConnectionOptions.Databases.Values)
{
if (!databaseInfo.IsUsedByTenants)
{
continue;
}
await DistributedEventBus.PublishAsync(
new ApplyDatabaseMigrationsEto
{
TenantId = id,
DatabaseName = databaseInfo.DatabaseName
}
);
}
}
}
}
And If write same code by just inheriting from SaasHostAppServiceBase
then all error goes away, but then I get runtime error as below :
[11:54:00 ERR] [null] The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'SCV.Litmus.LitmusTenants.CustomTenantAppService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Please suggest.
write your connection strings pls
Sorry I didn't get you !!!