p.ClrType == typeof(ExtraPropertyDictionary)
That was it. I was checking against string type only, would not expect such ClrType. Seems like I finally got rid of NVARCHAR. Thank you. I will keep this ticket open for some time until the migration is done...
And again you don't understand what I'm trying to say. I'm telling you that migration using a standard driver causes problem now. I have shown you the fragments of the code. Migration with Devart which has always been used never caused the problem. But now Devart cannot be used, they delay the NET7 support for month or so. You have published ABP7, but rely on Devart. Can you offer a working migration solution NOW?
Ok. But that was not my main question. My main question is why output generated by Devart differs from the standard one? They are supposed to be identical. Are you saying that output generated by standard driver is incorrect and cannot be used for Oracle migration??
Unfortunately, we don't have time and need to migrate now. So we need to use a generic Oracle driver.
The script which is generated by the generic driver, looks weird, though - it suggests to replace VARCHAR fields in ABP tables with NVARCHAR. There are a lot of such changes. Could you please explain, why in a 7.0.1 test app you are suggesting to use NVARCHAR/NVARCHAR2 DB type:
but at the same time the suggested Devart-based DB configuration has the following options, i.e. the DB fields are generated as VARCHAR/VARCHAR2?
So currently the generated migration script has tons of suggested changes like this (it compares the previously created migration using Devart and a generic dviver generation now):
I've tried to get rid of NVARCHAR manually in the DB migration context:
protected override void OnModelCreating(ModelBuilder builder)
{
//var config = Devart.Data.Oracle.Entity.Configuration.OracleEntityProviderConfig.Instance;
//config.Workarounds.DisableQuoting = true;
//config.CodeFirstOptions.UseNonLobStrings = true;
//config.CodeFirstOptions.UseNonUnicodeStrings = true;
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentityPro();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureLanguageManagement();
builder.ConfigureTextTemplateManagement();
builder.ConfigureBlobStoring();
builder.ConfigureSaas();
foreach (var property in builder.Model.GetEntityTypes().SelectMany(e => e.GetProperties()).Where(p => p.ClrType == typeof(string)))
{
property.SetIsUnicode(false);
}
}
But it still generates me migration script with NVARCHAR/NVARCHAR2...
This does not help either:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.DefaultTypeMapping<string>().IsUnicode(false);
}
hi
I think there is no problem with this.
Restore my question points then please if not done yet.
Eventually I've resolved thie issue. I've split the shared project DbContexts into 2 - one contains the entities which are shared in the consuming project, another one contains the entities which use the same table as the entities in the consuming project. Please, replenish my point for this question.
I've tried to resolved the issue with the code below (separating DbContexts):
public static void ConfigureCoreInternal(this ModelBuilder builder, Action<CoreModelBuilderConfigurationOptions> optionsAction = null)
...
EntityFramework Module:
[DependsOn(typeof(CoreDomainModule), typeof(AbpEntityFrameworkCoreModule))]
public class CoreEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<CoreDbContext>(options =>
{
options.AddDefaultRepository<ModuleLicence>();
options.AddDefaultRepository<CompanyLicence>();
options.AddDefaultRepository<Tenant>();
});
}
}
The method which does DB work:
public async Task<List<string>> GetAccessibleModulesAsync(int abxTenantId)
{
using (var uow = _unitOfWorkManager.Begin())
{
var tenants = await _tenantRepository.GetQueryableAsync();
var companyLicences = await _companyLicenceRepository.GetQueryableAsync();
var moduleLicences = await _moduleLicenceRepository.GetQueryableAsync();
var query = from tenant in tenants.Where(x => x.Id == abxTenantId).Take(1)
join companyLicence in companyLicences on tenant.CompanyId equals companyLicence.CompanyId
join moduleLicence in moduleLicences on companyLicence.LicenceId equals moduleLicence.LicenceId
select moduleLicence.ModuleId;
return query.Distinct().ToList();
}
}
Application Module where I add my custom class AbxPermissionChecker:
[DependsOn(...., typeof(CoreApplicationModule))]
public class CentralToolsApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<CentralToolsApplicationModule>();
});
....
context.Services.Replace(ServiceDescriptor.Transient<IPermissionChecker, AbxPermissionChecker>()); // REPLACING ABP PermissionChecker!
}
}
But still getting the above exception
What is a proper way of isolating entities in the DbContext of the project which is shared? Maybe this is the only root of the problem?
Or, I can keep using AppService - with RemoteService(IsEnabled = false)] as mentioned in my code, right? I do not expose NotificationAppService outside. In such case there's no difference between using it or converting it to DomainService, as far as I understand. I even don't inherit ApplicationService class...
Even if I use DomainService or Repository directly - how will it differ from using IApplicationService in the way I used it in terms of trust? I really need kind of pass "trust" from Received method into AppService (or other level) method where I would act on behalf of this user which usually is an authenticated ICurrentUser if used from frontend application. What I have at my disposal is just this user's Id and Tenant inside Received method.
I have a separate IdentityServer.
One of the projects has RabbitMQ receiver, where all other projects send the data too. This receiver needs to insert data into DB based on the received RabbitMQ input and it uses INotificationAppService in the same project to do that. See the code below.
When I do not use Authorization attribute - it of course works OK. But I want to make it work secure - i.e. if I do not use typical request authorization (since there is no request in question here) RabbitMQ needs to be trusted somehow inside AppService.
So what are your proposals again - even if you mean not to use AppService at all here? Could you please write a couple of code lines to describe the idea?
public override async Task<object> Received(BasicDeliverEventArgs @event)
{
var notificationCacheRabbitMqEto = @event.ToDataObject<NotificationRabbitMqEto>();
var hubContext = _serviceProvider.GetService<IHubContext<NotificationHub>>();
using (var scope = _serviceProvider.CreateScope())
{
try
{
var notificationAppService = scope.ServiceProvider.GetRequiredService<INotificationAppService>();
var newNotification = await notificationAppService.CreateAsync(new NotificationCreateDto
{
TenantId = notificationCacheRabbitMqEto.TenantId,
Login = notificationCacheRabbitMqEto.Login,
Level = (int)notificationCacheRabbitMqEto.Level,
Title = notificationCacheRabbitMqEto.Title,
Details = notificationCacheRabbitMqEto.Details,
IsActive = true,
IsImportant = notificationCacheRabbitMqEto.IsImportant,
CreatorName = GetTrimmedCreatorName(notificationCacheRabbitMqEto.Login), //Like so?
LastModifierName = GetTrimmedCreatorName(notificationCacheRabbitMqEto.Login) //Like so?
});
await hubContext.Clients.Group(notificationCacheRabbitMqEto.Login).SendAsync("notificationReceived", newNotification);
}
catch (Exception ex)
{
Log.Error(ex.Message);
}
}
return Task.FromResult<object>(null);
}
[RemoteService(IsEnabled = false)]
//[Authorize]
public class NotificationAppService : INotificationAppService
{
private readonly IServiceProvider _serviceProvider;
private readonly INotificationRepository _notificationRepository;
private readonly IStringLocalizer<CommonUIResource> _stringLocalizer;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IObjectMapper _objectMapper;
public NotificationAppService
(
IServiceProvider serviceProvider,
INotificationRepository notificationRepository,
IStringLocalizer<CommonUIResource> stringLocalizer,
IUnitOfWorkManager unitOfWorkManager,
IObjectMapper objectMapper
)
{
_serviceProvider = serviceProvider;
_notificationRepository = notificationRepository;
_stringLocalizer = stringLocalizer;
_unitOfWorkManager = unitOfWorkManager;
_objectMapper = objectMapper;
}
...
}
public interface INotificationAppService : IApplicationService, ITransientDependency {
...
}