Hello,
I have two more questions, Im reviewing class DistributedEventBusBase.cs
method protected virtual async Task<bool> AddToOutboxAsync(Type eventType, object eventData)
and i cant insert to AbpEventOutbox table values on ExtraProperties column when overriding the method.
My second question, Im working with google protobuff to publish binary messages on Azure Service Bus, using MyAzureDistributedEventBus from previous questions, and casting Etos to proto generated classes before publishing on Azure Service Bus. I dont know if it is possible to instead of working on distributed events with Etos and IEntityEto<TKey> interface, is possible to work with a custom interface or a IMessage interface from google protobuff protocol.
Thanks
Hello,
What I mean is whether applications by default can only publish to one topic. So, for two applications to communicate through Azure Service Bus, would they both publish and consume all their events from all their aggregates in the same topic? And what I mean is about the structure of Topics, Subscriptions, and Queues in Azure for the communication of both applications.
Then, regarding multitenancy, I have a question. If I have Application 1 with tenants A and B, and Application 2 with tenants A and B, and the messages published in Azure Service Bus comply with the interfaces you mentioned (IMultitenant or IEventDataMayHaveTenantId), how does Application 2 know which tenant a message published by Application 1 belongs to if the internal IDs of their Tenants in their SaasTenants tables are different in both applications?
Thanks, and sorry for the confusion.
Hello, works fine but i have doubts about it, following your approach of publishing in a single topic for all events generated by all aggregates. For a second application also using Abp, multitenancy, and the outbox and inbox patterns, which wants to integrate with the first application through Azure Service Bus and consume messages from a certain type of aggregate or event. How is the topology managed in Azure? How does the second application know which of its tenants each message published by the first application corresponds to? What is the standard way that Abp has to communicate applications with Service Bus and the outbox and inbox patterns?
Thanks
I will try to implement a custom AzureDistributedEventBus following your code.
Thank you
Hi, Im using distributed event bus with outbox pattern and Azure service bus provider. I have 3 requirements that I'm struggling to implement with AzureDistributedEventBus.
The first is the need to publish to different topics based on the event name of the Eto:
[EventName("projects")] public class ProjectEto
[EventName("campaigns")] public class CampaignEto
The second is whether there's a way to override part of the message publishing with AzureDistributedEventBus to achieve the following: With the default implementation of the outbox pattern, when publishing the message to Azure Service Bus, override the message publishing to choose which topic the message corresponds to. Additionally, be able to, if the topic or subscription don't exist, create them programmatically using ServiceBusAdministrationClient.CreateTopicAsync from Azure.Messaging.ServiceBus.Administration.
The last one, because is posible to use outbox pattern with no Sql database/context, so my last question is if i can configure the pattern to not delete the rows in AbpEventOutbox table after publishing on azure and mark as published instead of delete.
Thank you!
Hello,
I'm using AbpBackgroundJobs for tasks that mainly involve generating a PDF certificate, attaching it to an email, and sending it via email through Azure Communication Services in bulk. Around 2000 jobs are queued on average in this operation.
To avoid exceeding the limits of Exchange 365 in email sending (30 emails per minute), I'm queuing the jobs with a 15-second delay between each consecutive one.
During the execution, I've noticed that the 15-second delay isn't always respected, and I've also observed that the execution order of the jobs doesn't strictly follow the NextTryTime. What logic does the polling on the BackgroundJobs table use to select the job to execute?
Here's the scenario: there are 10 jobs with NextTryTime before the current date, and then there are others with NextTryTime after the current date. In what order will they be executed?
If it's not possible to enforce the delay when enqueuing, as job execution times are sometimes less than the planned delay, is it possible to introduce a delay when the job is selected for execution to avoid mailbox saturation?
Finally, with the aim of scaling the application, as it's multi-tenant, is there a possibility for each tenant to have its dedicated background jobs thread independent of other tenants?
Thank you and regards,
Hi, I need to restrict the acces in each tenant to a setting value in settings management. Im trying to make a SettingComponentGroup, only visible for a settings admin user, wich could be a role created for this purpose. Following your example:
`
public class BookStoreSettingPageContributor : ISettingPageContributor{
public Task ConfigureAsync(SettingPageCreationContext context)
{
context.Groups.Add(
new SettingPageGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupViewComponent),
order : 1
)
); return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingPageCreationContext context)
{
// You can check the permissions here
return Task.FromResult(true);
}
} `
How i can in CheckPermissionsAsync, make "MySettingGroup" only visible for an specific role? Wich is the correct way to do it?
Thank you
hello,
i tried this
ObjectHelper.TrySetProperty(certificateRecord, x => x.CreatorId, () => YourId);
await _certificateRepository.InsertAsync(certificateRecord);
And it works fine.
Thank you!
hi, yes sure, basically sends an email and then inserts a domain entity and marks as processed, or sending email error if there's an error.
public class CertificateEmailSendingJob : AsyncBackgroundJob<CertificateEmailSendingArgs>, ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ISettingProvider _settingsProvider;
private readonly ICurrentTenant _currentTenant;
private readonly IDonationCertificateRepository _certificateRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
public CertificateEmailSendingJob(IEmailSender emailSender,
ISettingProvider settingsProvider,
ICurrentTenant currentTenant,
IDonationCertificateRepository certificateRepository,
IUnitOfWorkManager unitOfWorkManager,
ICurrentPrincipalAccessor currentPrincipalAccessor)
{
_emailSender = emailSender;
_settingsProvider = settingsProvider;
_currentTenant = currentTenant;
_certificateRepository = certificateRepository;
_unitOfWorkManager = unitOfWorkManager;
_currentPrincipalAccessor = currentPrincipalAccessor;
}
public override async Task ExecuteAsync(CertificateEmailSendingArgs args)
{
var claims = JobsExtensions.GetUserAsync(args.User.Id, args.User.Name, args.User.Surname, args.User.UserName, args.User.Roles);
using (_currentPrincipalAccessor.Change(claims.claims))
{
using (_currentTenant.Change(args.TenantId))
{
var from = await _settingsProvider.GetOrNullAsync(FundraisingSettingsConst.SmtpUserName);
using var memoryStream = new MemoryStream(args.CertificateFile);
var attachment = new Attachment(memoryStream, new ContentType(MediaTypeNames.Application.Pdf))
{
ContentDisposition = { FileName = args.CertificateFileName }
};
var message = new MailMessage(
from,
args.DonorEmail,
args.EmailSubject,
args.EmailBody);
message.Attachments.Add(attachment);
using var uow = _unitOfWorkManager.Begin(
requiresNew: true, isTransactional: false);
try
{
await _emailSender.SendAsync(message);
var certificateRecord =
new DonationCertificate(Guid.NewGuid(), args.DonorId, args.LabelId,
args.EmailTemplateLabelId,
DonationCertificateStatus.Processed,
args.Year,
args.DonationId);
await _certificateRepository.InsertAsync(certificateRecord);
}
catch (Exception)
{
var certificateRecord =
new DonationCertificate(Guid.NewGuid(), args.DonorId, args.LabelId,
args.EmailTemplateLabelId,
DonationCertificateStatus.EmailSendingError,
args.Year,
args.DonationId);
await _certificateRepository.InsertAsync(certificateRecord);
}
await uow.CompleteAsync();
}
}
}
}
public static class JobsExtensions
{
public static (Guid? userId, ClaimsPrincipal claims) GetUserAsync(Guid? userId, string name, string surname, string userName, string[] roleNames)
{
var claimsList = new List<Claim>
{
new(AbpClaimTypes.UserId, userId.ToString()),
new(AbpClaimTypes.Name, name ?? "BackgroundJobUser"),
new(AbpClaimTypes.SurName, surname ?? "BackgroundJobUser"),
new(AbpClaimTypes.UserName, userName)
};
claimsList.AddRange(roleNames
.Select(_ => new Claim(AbpClaimTypes.Role, _)).ToList());
return (userId, new ClaimsPrincipal(new ClaimsIdentity(claimsList)));
}
}
public class CertificateEmailSendingArgs
{
public Guid? TenantId { get; set; }
public string DonorEmail { get; set; }
public string EmailSubject { get; set; }
public string EmailBody { get; set; }
public string CertificateFileName { get; set; }
public byte[] CertificateFile { get; set; }
public Guid DonorId { get; set; }
public Guid LabelId { get; set; }
public Guid EmailTemplateLabelId { get; set; }
public int? Year { get; set; }
public Guid? DonationId { get; set; }
public UserArgs User { get; set; }
}
internal class DonationCertificateRepository: EfCoreRepository<FundraisingDbContext, DonationCertificate, Guid>,IDonationCertificateRepository
I tried to switch order of change tenant and change user, same result, CreatorId is null. Something i should be doing wrong changing user, because values when i generate ClaimsPrincipal are correct.