Running `IContentManager.PublishAsync(..)` outside of `Controller` doesn't trigger Workflow Event
Describe the bug
Running IContentManager.PublishAsync(..) outside of Controller doesn't trigger Workflow Event, when executed by Hangfire.io runner.
From my controller I enqueue a task:
hangfireClient.Schedule<GeneratedAlbumContainer>(x => x.ProcessJob(jobModel), new TimeSpan(0, 0, 0 * 30));
public async Task ProcessJob(JobModel jobModel) {
var job = await _contentManager.GetAsync(jobModel.JobId, VersionOptions.DraftRequired);
job.Content.Job.Status.Text = "running";
await _contentManager.UpdateAsync(job);
await _contentManager.PublishAsync(job);
await _session.SaveChangesAsync();
}
I tried manualy triggering the workflow event, by adding the following code to the end of ProcessJob:
var name = nameof(ContentPublishedEvent);
var contentEvent = new ContentEventContext() {
Name = name,
ContentType = job.ContentType,
ContentItemId = job.ContentItemId,
ContentItemVersionId = job.ContentItemVersionId,
};
var input = new Dictionary<string, object>{
{ ContentEventConstants.ContentItemInputKey, job },
{ ContentEventConstants.ContentEventInputKey, contentEvent }
};
await _workflowManager.TriggerEventAsync(name, input, job.ContentItemId);
This result in an NRE:
System.NullReferenceException: Object reference not set to an instance of an object.
at OrchardCore.Templates.Services.PreviewTemplatesProvider.<>c__DisplayClass1_0.<.ctor>b__0()
at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)
This, I'm guessing, comes from different DI scopes. How can I modify my code to trigger the workflow event?
in general from a background job managed by a library like hangfire.io, you must create a shell scope and then execute anything in that context.
@MichaelPetrinolis can you elaborate or point me to some documentation? I'm here to learn :)
We triaged this issue and set the milestone according to the priority we think is appropriate (see the docs on how we triage and prioritize issues).
This indicates when the core team may start working on it. However, if you'd like to contribute, we'd warmly welcome you to do that anytime. See our guide on contributions here.
I helped you with this on Discord. Please elaborate here what you tried from that.
Yeah, hi there!
So I tried accessing ShellScope.Current and injecting IShellScope. The first was NRE and the other failed to resolve.
I also tried to manualy resolve the dependencies, but this didn't trigger the Workflow events in OC since it's a different context.
It seems that this issue didn't really move for quite a while despite us asking the author for further feedback. Is this something you'd like to revisit any time soon or should we close? Please reply.
Hi, circling back on this
It seems that this issue didn't really move for quite a while despite us asking the author for further feedback. Is this something you'd like to revisit any time soon or should we close? Please reply.
Describe the bug
Running
IContentManager.PublishAsync(..)outside ofControllerdoesn't trigger Workflow Event, when executed by Hangfire.io runner.From my controller I enqueue a task:
hangfireClient.Schedule<GeneratedAlbumContainer>(x => x.ProcessJob(jobModel), new TimeSpan(0, 0, 0 * 30));public async Task ProcessJob(JobModel jobModel) { var job = await _contentManager.GetAsync(jobModel.JobId, VersionOptions.DraftRequired); job.Content.Job.Status.Text = "running"; await _contentManager.UpdateAsync(job); await _contentManager.PublishAsync(job); await _session.SaveChangesAsync(); }I tried manualy triggering the workflow event, by adding the following code to the end of
ProcessJob:var name = nameof(ContentPublishedEvent); var contentEvent = new ContentEventContext() { Name = name, ContentType = job.ContentType, ContentItemId = job.ContentItemId, ContentItemVersionId = job.ContentItemVersionId, }; var input = new Dictionary<string, object>{ { ContentEventConstants.ContentItemInputKey, job }, { ContentEventConstants.ContentEventInputKey, contentEvent } }; await _workflowManager.TriggerEventAsync(name, input, job.ContentItemId);This result in an NRE:
System.NullReferenceException: Object reference not set to an instance of an object. at OrchardCore.Templates.Services.PreviewTemplatesProvider.<>c__DisplayClass1_0.<.ctor>b__0() at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)This, I'm guessing, comes from different DI scopes. How can I modify my code to trigger the workflow event?
THe object reference error is likely because there's no httpcontext. you will need to create one like they do for background task triggers.
https://github.com/OrchardCMS/OrchardCore/blob/ad59b78c8f03c6a23cc34e830f9705bc7b884d7f/src/OrchardCore/OrchardCore.Abstractions/BackgroundTasks/ShellContextExtensions.cs#L12
Here's how I trigger events from background workers
using (ShellScope shellScope = await _shellHost.GetScopeAsync("Default"))
{
await shellScope.UsingAsync(async scope =>
{
if (scope != null)
{
_httpContextAccessor.HttpContext = scope.ShellContext.CreateHttpContext();
IWorkflowManager manager = scope.ServiceProvider.GetRequiredService<IWorkflowManager>();
var messageData = new Dictionary<string, object>
{
{ "value", cr.Message.Value is null ? "" : cr.Message.Value.ToString() },
{ "key", cr.Message.Key is null ? "" : cr.Message.Key.ToString() },
{ "topic", cr.Topic }
};
await manager
.TriggerEventAsync(KafkaMessageEvent.EventName, messageData);
}
});
}