Hi all...
I have some issues using Hangfire when I need to access Database. I've read here that I maybe shouldn't use HangFire to call Application Service but I don't see how I could do what I want to do another way.
Actually I have in my Startup.cs from my Web project :
[...]
app.UseHangfireDashboard();
app.UseHangfireServer();
RecurrentJobs recurrentJobs = new RecurrentJobs(IocManager.Instance);
RecurringJob.AddOrUpdate(() => recurrentJobs.LaunchJobsRecurrentFiveMinutes(), "0,5,10,15,20,25,30,35,40,45,50,55 * * * *");
[...]
In the RecurrentJobs.cs file, I have this call, which try to call a method in the ApplicationService ("AjouterMessageSysteme") :
[...]
[UnitOfWork]
public void LaunchJobsRecurrentFiveMinutes()
{
[...]
using (var messageService = _iocResolver.ResolveAsDisposable<MessageAppService>())
{
var source = LocalizationHelper.Manager.GetSource("MyProject");
foreach (var concoursId in retourMajQualif.ListeIdConcoursQualifMaj)
{
messageService.Object.AjouterMessageSysteme(
new AjouterMessageInput
{
ConcoursId = concoursId,
Contenu = source.GetString("finQualifications")
});
}
}
[...]
}
}
[...]
In the MessageAppService.cs I have this code :
[...]
public AjouterMessageOutput AjouterMessageSysteme(AjouterMessageInput input)
{
var concours = _concoursRepository.GetAllWithParticipants().Where(c => c.Id == input.ConcoursId).FirstOrDefault();
foreach (var part in concours.ListeParticipants)
{
_messageRepository.Insert(new Message
{
ConcoursId = input.ConcoursId,
Contenu = input.Contenu,
DestinataireId = part.UserId,
EnvoyeurId = 0
});
}
return new AjouterMessageOutput();
}
[...]
The issue is when I call the method " _concoursRepository.GetAllWithParticipants()", which call a GetAll() with some includes. The object "concours " is always disposed before it can be used. I guess it's because the whole process isn't a "Unit Of Work", but I don't know how I can declare it beside the annotation on method in the class "RecurrentJobs". I succesfully could call a procedure from database, but I can't get data. Of course, if the method of the application service is called from a controller, it works perfectly.
Is there a way I can do this, or ABP/HangFire isn't designed to work like this ?
I apologize for my approximative english, thanx in advance for any help.
3 Answer(s)
-
0
I found a way, in the RecurrentJobs.cs file, using the "Object.UnitOfWorkManager" of my appService.
[...] public void LaunchJobsRecurrentFiveMinutes() { [...] using (var messageService = _iocResolver.ResolveAsDisposable<MessageAppService>()) { var source = LocalizationHelper.Manager.GetSource("MyProject"); using (var unitOfWork = messageService.Object.UnitOfWorkManager.Begin()) { foreach (var concoursId in retourMajQualif.ListeIdConcoursQualifMaj) { messageService.Object.AjouterMessageSysteme( new AjouterMessageInput { ConcoursId = concoursId, Contenu = source.GetString("finQualifications") }); } unitOfWork.Complete(); } } [...] } } [...]
I hope it's not bad coding, and if it's not, that it could help someone else !
-
0
Hi,
While your code works, I want to make 2 suggestions for a better practice:
- If you need to IUnitOfWorkManager, inject it into your class and use it. Not use application service's object.
- Do not use application services from background jobs. App services has audit logging, validation, authorization... features you probably don't need in a background service. App service should be user by user interface. If you need logic in your app service, you can extract this logic into a domain service and use this domain service both from the app service and background job.
-
0
Thank you for your answer Hikalkan.
Honestly, I don't know how to do this, I don't fully understand how works all this injection principle with Castle Windsor. Could you point me to an example code of this ?
What I try to acheive with HangFire is to use a background job instead of a windows service. Is it such a bad idea ? I need something which runs every x minutes, update some data in the database, then get data from it, and finally insert some data in. When you're talking about using a domain service where the logic would be, are you talking about the "Core" domain of the template ? You're meaning that my background job should "talk" directly to the "Core" instead of the application service ?