Hon.IFS.SiteManagement.EntityFrameworkCore.Domains.Contacts.ContactRepositoryTests.GetListAsync Source: ContactRepositoryTests.cs line 21 Duration: 1 ms
Message: Volo.Abp.AbpInitializationException : An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Hon.IFS.SiteManagement.SiteManagementTestBaseModule, Hon.IFS.SiteManagement.TestBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: Object reference not set to an instance of an object.. See the inner exception for details. ---- System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
ModuleManager.InitializeModules(ApplicationInitializationContext context)
AbpApplicationBase.InitializeModules()
AbpApplicationWithExternalServiceProvider.Initialize(IServiceProvider serviceProvider)
AbpIntegratedTest1.ctor() SiteManagementTestBase1.ctor()
SiteManagementEntityFrameworkCoreTestBase.ctor()
ContactRepositoryTests.ctor() line 14
RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
----- Inner Stack Trace -----
SiteManagementDataSeedContributor.SeedAsync(DataSeedContext context) line 58
<11 more frames...>
ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
TaskExtensions.WaitAndUnwrapException(Task task)
AsyncContext.Run(Func1 action) AsyncHelper.RunSync(Func1 action)
SiteManagementTestBaseModule.SeedTestData(ApplicationInitializationContext context) line 32
SiteManagementTestBaseModule.OnApplicationInitialization(ApplicationInitializationContext context) line 27
OnApplicationInitializationModuleLifecycleContributor.Initialize(ApplicationInitializationContext context, IAbpModule module)
ModuleManager.InitializeModules(ApplicationInitializationContext context)
[RemoteService(IsEnabled = false)] public abstract class SendGridEmailNotificationAppServiceBase : SiteHostAppService { protected IEmailSender _emailSender; private readonly ITemplateRenderer _templateRenderer; private readonly Microsoft.Extensions.Configuration.IConfiguration _configuration; private readonly ITenantRepository _tenantRepository; private readonly ICurrentTenant _currentTenant; private readonly IStringEncryptionService _stringEncryption;
public SendGridEmailNotificationAppServiceBase(IEmailSender emailSender, ITemplateRenderer templateRenderer,
Microsoft.Extensions.Configuration.IConfiguration configuration, ITenantRepository tenantRepository, ICurrentTenant currentTenant, IStringEncryptionService stringEncryption)
{
_emailSender = emailSender;
_templateRenderer = templateRenderer;
_configuration = configuration;
_tenantRepository = tenantRepository;
_currentTenant = currentTenant;
_stringEncryption = stringEncryption;
}
public virtual async Task EmailNotification(SendGridEmailNotificationDto input)
{
string emailBody = null!;
input.BaseSiteUrl = _configuration["App:SelfUrl"]?.Trim();
try
{
if (input.MailSubject.Equals("CHANGEPASSWORD", StringComparison.InvariantCultureIgnoreCase))
{
input.MailSubject = "Your Password Has Been Successfully Changed";
var model = new ChangePasswordModel
{
Name = input.Name,
Url = input.BaseSiteUrl + "/Account/login",
Type = input.Type,
TenantName = input.TenantName
};
model.setCurrentDateTime();
emailBody = await LoadTemplate("ChangePassword.tpl", model);
}
else if (input.MailSubject.Equals("NEWUSERCREATED", StringComparison.InvariantCultureIgnoreCase))
{
input.MailSubject = "Your IFS Account Details and Next Steps";
var angularUrl = _configuration["App:SelfUrl"]?.Trim()?.TrimEnd('/');
if (string.IsNullOrEmpty(angularUrl))
{
throw new InvalidOperationException("App:AngularUrl is not set in configuration.");
}
string tenantHostName = await GetTenantHostNameAsync();
string navigationUrl;
if (_currentTenant.Id.HasValue)
{
string encryptedtenantHostName = _stringEncryption.Encrypt(tenantHostName);
navigationUrl = $"{angularUrl}/Account/Login?tenantName={Uri.EscapeDataString(encryptedtenantHostName)}";
}
else
{
navigationUrl = $"{angularUrl}/Account/Login";
}
var model = new UserCreationModel
{
Email = input.MailTo,
Username = input.Username,
Name = input.Name,
TenantId = input.TenantId,
UserId = input.Id,
Password = input.Password,
Url = navigationUrl
};
emailBody = await LoadTemplate("UserCreation.tpl", model);
}
else
{
throw new UserFriendlyException("Unsupported email subject type.");
}
await _emailSender.SendAsync(
to: input.MailTo,
subject: input.MailSubject,
body: emailBody,
isBodyHtml: input.IsBodyHtml
);
}
catch (Exception ex)
{
Logger.LogError(ex, "An error occurred while sending the email notification.");
throw new UserFriendlyException($"Failed to send the email. Reason: {ex.Message}. Please try again later.");
}
}
private async Task<string> LoadTemplate(string templateName, object model)
{
string renderedContent = null!;
try
{
if (string.IsNullOrWhiteSpace(templateName))
{
throw new UserFriendlyException("Template name is invalid.");
}
string templateDirectory;
var isDevEnv = Convert.ToBoolean(_configuration["IsDevEnv"] ?? "false");
templateDirectory = isDevEnv
? Path.Combine(Directory.GetCurrentDirectory(), "Emailing", "Templates")
: Path.Combine(AppContext.BaseDirectory, "Emailing", "Templates");
string templatePath = Path.Combine(templateDirectory, templateName);
if (!File.Exists(templatePath))
{
throw new FileNotFoundException($"Email template not found at path: {templatePath}");
}
var templateContent = await File.ReadAllTextAsync(templatePath);
// Apply replacements based on template name
if (templateName.Equals("UserCreation.tpl", StringComparison.OrdinalIgnoreCase) && model is UserCreationModel userModel)
{
renderedContent = templateContent
.Replace("{{model.Name}}", userModel.Name)
.Replace("{{model.Email}}", userModel.Email)
.Replace("{{model.Username}}", userModel.Username)
.Replace("{{model.Password}}", userModel.Password)
.Replace("{{model.Url}}", userModel.Url);
}
else if (templateName.Equals("ChangePassword.tpl", StringComparison.OrdinalIgnoreCase) && model is ChangePasswordModel passwordModel)
{
renderedContent = templateContent
.Replace("{{model.Name}}", passwordModel.Name)
.Replace("{{model.Date}}", passwordModel.Date.ToString("MMMM d, yyyy 'at' h:mm tt"))
.Replace("{{model.TenantName}}",passwordModel.TenantName)
.Replace("{{model.Url}}", passwordModel.Url);
}
else
{
throw new UserFriendlyException($"Unsupported template or model type for: {templateName}");
}
return renderedContent;
}
catch (Exception ex)
{
Logger.LogInformation(renderedContent);
Logger.LogError(ex, $"Failed to load or process email template: {templateName}");
throw new UserFriendlyException($"An error occurred while preparing the email content. --> {ex.Message}");
}
}
private async Task<string> GetTenantHostNameAsync()
{
string tenantHostName = "default";
if (_currentTenant.Id.HasValue)
{
var tenant = await _tenantRepository.FindAsync(_currentTenant.Id.Value);
if (tenant?.ExtraProperties.TryGetValue("tenantHostName", out var hostNameObj) == true)
{
tenantHostName = hostNameObj?.ToString() ?? tenantHostName;
}
}
return tenantHostName;
}
" private async Task<string> RenderEmailBodyAsync(string templateName, object model) { string renderedBody = null!; try { // Render the email body using the template renderer renderedBody = await _templateRenderer.RenderAsync(templateName, model); return renderedBody; } catch (Exception ex) { // Log the error and rethrow a user-friendly exception //Logger.LogError(ex, $"Failed to render email template: {templateName}"); throw new UserFriendlyException($"renderedBody string = {renderedBody} --> {ex.ToString()} for template {templateName} An error occurred while preparing the email content."); }" }
}
Hi,
We have 2 host applications (Host 1 and Host 2). Both have their respective Document Management Module 1 -> Host 1 and Document Management Module 2 -> Host 2. I would like to leverage the Document Management Module 1 in Host 1 and Host 2 rather than creating 2 different modules like above statement.
Unable to generate the ABP Elsa Pro domain entities after integrating with Modular API solution. Please share the step by step documentation
Check the docs before asking a question: https://abp.io/docs/latest Check the samples to see the basic tasks: https://abp.io/docs/latest/samples The exact solution to your question may have been answered before, and please first use the search on the homepage.
Provide us with the following info:
🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.
Hi,
I am unable to create proxy and angular components for newly created entities via ABP suite. This is a completely new module under one host application and another module under the same host application, we do not see the these issues.
Appreciate for the quick response.
Please let me know if any logs required to analyze it.
Check the docs before asking a question: https://abp.io/docs/latest Check the samples to see the basic tasks: https://abp.io/docs/latest/samples The exact solution to your question may have been answered before, and please first use the search on the homepage.
Provide us with the following info:
🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.
When creating a new tenant via the ABP Tenant Management API (POST /api/tenant-management/tenants) from an external application, the tenant and admin user are created successfully. However, after logging in as the newly created admin user, the user is unable to create additional users due to missing permissions or role assignment.
This suggests that role-to-user mapping is not being applied automatically during tenant creation when the API is called externally (e.g., from Postman, another service, or automated script), even though the same call works correctly when made via Swagger or ABP UI. here is the example payload we are passing from other abp application { "name": "Tenant30", "tenantType": 0, "editionId": "Basic", "activationState": 0, "adminEmailAddress": "itp@gmail.com", "adminPassword": "Password@123", "extraProperties": { "subscriptionPlan": 0, "contact": "09876543210", "adminName": "Vasudha Gurram", "tenantHostName": "T30", "adminEmail": "itp@gmail.com", "firstName": "Vasudha", "lastName": "Gurram", "description": null, "country": "India", "region": "HYD" } }
I'm encountering an issue with SendGrid email delivery in my application when deployed to Azure. The problem occurs specifically in a layered (multi-tier) architecture, while the same code works perfectly in a single-layer setup and also functions correctly in local development environments.
Do we need configure an Extra in Layred solution
For Your Referance I have added the code
namespace Hon.IFS.SiteManagement.SiteRiskIndices
{
[RemoteService]
public abstract class SiteRiskIndexAppService : SiteManagementAppService ,ITransientDependency
{
#region Initialization and Constructor
private readonly RiskIndexManager _riskIndexManager;
private readonly IRiskIndexRepository _riskIndexRepository; // Add this field
public SiteRiskIndexAppService(IRiskIndexRepository riskIndexRepository, RiskIndexManager riskIndexManager) // Update constructor
{
_riskIndexManager = riskIndexManager;
_riskIndexRepository = riskIndexRepository; // Initialize the repository
}
#endregion
#region BUlK CREATE RISK INDICES
[Authorize(SiteManagementPermissions.RiskIndices.Create)]
public async Task<List<RiskIndexDto>> CreateBulkRiskIndicesAsync(Guid siteId, List<Guid> buildingIds)
{
var random = new Random();
var createdRiskIndices = new List<RiskIndexDto>();
foreach (var buildingId in buildingIds)
{
// Generate random values with 2 decimal places for each field
var communityRiskIndex = Math.Round(random.NextDouble() * 100, 2); // Define communityRiskIndex
var neighbourhoodRiskIndex = Math.Round(random.NextDouble() * 100, 2); // Define neighbourhoodRiskIndex
var buildingRiskIndex = Math.Round(random.NextDouble() * 100, 2);
var buildingRiskIndexPercentage = 20;
var historicalFireIncident = random.Next(0, 11); // Integer between 0-10
var historicalFireIncidentPercentage = 10;
var maintenance = Math.Round(random.NextDouble() * 100, 2);
var maintenancePercentage = 10;
var fireSupression = Math.Round(random.NextDouble() * 100, 2);
var fireSupressionPercentage = 10;
var fireService = Math.Round(random.NextDouble() * 100, 2);
var fireServicePercentage = Math.Round(random.NextDouble() * 100, 2);
var buildingOrg = Math.Round(random.NextDouble() * 100, 2);
var buildingOrgPercentage = 10;
var passiveFire = Math.Round(random.NextDouble() * 100, 2);
var passiveFirePercentage = 10;
var detection = Math.Round(random.NextDouble() * 100, 2);
var detectionPercentage = 10;
var ignition = Math.Round(random.NextDouble() * 100, 2);
var ignitionPercentage = 10; // Ensure ignitionPercentage is included
var riskIndexScore = (buildingRiskIndex * buildingRiskIndexPercentage)
+ (historicalFireIncident * historicalFireIncidentPercentage)
+ (maintenance * maintenancePercentage)
+ (fireSupression * fireSupressionPercentage)
+ (fireService * fireServicePercentage)
+ (buildingOrg * buildingOrgPercentage)
+ (passiveFire * passiveFirePercentage)
+ (detection * detectionPercentage)
+ (ignition * ignitionPercentage);
// Create risk index for the building
var riskIndex = await _riskIndexManager.CreateAsync(
siteId, buildingId,
(decimal)communityRiskIndex, (decimal)neighbourhoodRiskIndex, // Use the defined variables
(decimal)buildingRiskIndex, (decimal)buildingRiskIndexPercentage,
historicalFireIncident, (decimal)historicalFireIncidentPercentage,
(decimal)maintenance, (decimal)maintenancePercentage,
(decimal)fireSupression, (decimal)fireSupressionPercentage,
(decimal)fireService, (decimal)fireServicePercentage,
(decimal)buildingOrg, (decimal)buildingOrgPercentage,
(decimal)passiveFire, (decimal)passiveFirePercentage,
(decimal)detection, (decimal)detectionPercentage,
(decimal)ignition, (decimal)ignitionPercentage, // Pass ignitionPercentage here
(decimal)riskIndexScore
);
createdRiskIndices.Add(ObjectMapper.Map<RiskIndex, RiskIndexDto>(riskIndex));
}
return createdRiskIndices;
}
[Authorize(SiteManagementPermissions.RiskIndices.Default)]
public async Task<List<RiskIndexDto>> GetListBySiteAndBuildingsAsync(Guid siteId, List<Guid> buildingIds)
{
// Create a query to filter by siteId
var query = await _riskIndexRepository.GetQueryableAsync();
query = query.Where(ri => ri.SiteId == siteId);
// Further filter by buildingIds if provided
if (buildingIds != null && buildingIds.Any())
{
query = query.Where(ri => buildingIds.Contains(ri.BuildingId));
}
// Execute the query and retrieve the results
var items = await AsyncExecuter.ToListAsync(query);
// Map the results to DTOs and return
return ObjectMapper.Map<List<RiskIndex>, List<RiskIndexDto>>(items);
}
#endregion
}
}
I have done it like this: Reference Code below
public virtual async Task<SaasTenantDto> CreateSiteTenanatAsync(SaasTenantCreateDto input)
{
input.ConnectionStrings = await NormalizedConnectionStringsAsync(input.ConnectionStrings);
Tenant tenant = null;
async Task CreateTenantAsync()
{
tenant = await TenantManager.CreateAsync(input.Name, input.EditionId);
if (!input.ConnectionStrings.Default.IsNullOrWhiteSpace())
{
tenant.SetDefaultConnectionString(input.ConnectionStrings.Default);
}
if (input.ConnectionStrings.Databases != null)
{
foreach (var database in input.ConnectionStrings.Databases)
{
tenant.SetConnectionString(database.DatabaseName, database.ConnectionString);
}
}
await CheckConnectionStringAsync(tenant);
input.MapExtraPropertiesTo(tenant);
tenant.SetActivationState(input.ActivationState);
if (tenant.ActivationState == TenantActivationState.ActiveWithLimitedTime)
{
tenant.SetActivationEndDate(input.ActivationEndDate);
}
/* Auto saving to ensure TenantCreatedEto handler can get the tenant! */
await TenantRepository.InsertAsync(tenant, autoSave: true);
}
if (input.ConnectionStrings.Default.IsNullOrWhiteSpace() &&
input.ConnectionStrings.Databases.IsNullOrEmpty())
{
/* 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();
}
}
var adminName = "admin"; // default
if (input.ExtraProperties.TryGetValue("adminName", out var nameObj) && nameObj is string nameStr && !string.IsNullOrWhiteSpace(nameStr))
{
adminName = nameStr;
}
await DistributedEventBus.PublishAsync(
new TenantCreatedEto
{
Id = tenant.Id,
Name = tenant.Name,
Properties =
{
{"AdminEmail", input.AdminEmailAddress},
{"AdminPassword", input.AdminPassword},
** { "AdminName", adminName}** Added this line still not working
}
}
);
return ObjectMapper.Map<Tenant, SaasTenantDto>(tenant);
}
We are programmatically creating directories and uploading files from another part of our application. The directories and files appear correctly in the ABP File Management module, confirming successful storage However, we are experiencing issues when trying to download these files from abp file management module.
Reference Code: private async Task<FileDescriptor> UploadFileAsync(SiteFile file, Guid directoryId) { if (file == null) throw new UserFriendlyException("Invalid file provided.");
// Convert the byte array to a Base64 string
string fileContentBase64 = Convert.ToBase64String(file.Content);
byte[] fileBytes = Convert.FromBase64String(fileContentBase64);
var fileDescriptor = new FileDescriptor(
id: GuidGenerator.Create(),
name: file.Name,
mimeType: file.MimeType,
directoryId: directoryId,
size: fileBytes.Length,
tenantId : _currentTenant?.Id
);
await _fileDescriptorRepository.InsertAsync(fileDescriptor);
using var stream = new MemoryStream(fileBytes);
await _blobContainer.SaveAsync(fileDescriptor.Id.ToString(), stream);
return fileDescriptor;
}
public class SiteFile : FullAuditedEntity<Guid> {
public Guid Id { get; set; }
public string? planType { get; set; }
public string Name { get; set; }
public string MimeType { get; set; }
public long Size { get; set; }
public byte[] Content { get; set; }
}