Wiggy
05/14/2024, 11:48 AMSystem.AggregateException: One or more errors occurred. (No AmbientContext was found.) ---> System.InvalidOperationException: No AmbientContext was found. at Umbraco.Cms.Infrastructure.Scoping.AmbientScopeContextStack.Pop() at Umbraco.Cms.Infrastructure.Scoping.ScopeProvider.PopAmbientScopeContext() at Umbraco.Cms.Infrastructure.Scoping.Scope.<>c__DisplayClass100_0.<RobustExit>g__HandleScopeContext|2() at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions) --- End of inner exception stack trace --- at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions) at Umbraco.Cms.Infrastructure.Scoping.Scope.RobustExit(Boolean completed, Boolean onException) at Umbraco.Cms.Infrastructure.Scoping.Scope.DisposeLastScope() at Umbraco.Cms.Infrastructure.Scoping.Scope.Dispose() at Umbraco.Cms.Infrastructure.Examine.ExamineUmbracoIndexingHandler.DeferedReIndexForContent.<>c__DisplayClass6_0.<Execute>b__0(CancellationToken cancellationToken) at Umbraco.Cms.Infrastructure.HostedServices.QueuedHostedService.BackgroundProcessing(CancellationToken stoppingToken)
Trying to run a Hangfire task to update a node with the ContentService.
Have tried a million things regarding scopes etc.Wiggy
05/14/2024, 11:48 AMSebastiaan
05/14/2024, 11:49 AMSebastiaan
05/14/2024, 11:49 AMWiggy
05/14/2024, 11:51 AMSebastiaan
05/14/2024, 11:51 AMContentService
is described here: https://cultiv.nl/blog/using-hangfire-to-update-umbraco-content/Sebastiaan
05/14/2024, 11:51 AMWiggy
05/14/2024, 11:51 AMSebastiaan
05/14/2024, 11:52 AMSebastiaan
05/14/2024, 11:53 AMWiggy
05/14/2024, 11:55 AMSebastiaan
05/14/2024, 11:55 AMWiggy
05/14/2024, 12:14 PMcsharp
using Application.Core.OpeningHours.BankHolidays;
using Application.Hangfire;
using Hangfire;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Composing;
namespace Application.Core.OpeningHours;
public class OpeningHoursComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.AddTransient<BankHolidayImportTask>();
RunHangfire(builder);
}
private void RunHangfire(IUmbracoBuilder builder)
{
// Extra check whether Hangfire is enabled otherwise it will fail as the composer still tries to register the jobs
builder.Services.Configure<HangfireOptions>(options =>
builder.Config.GetSection(HangfireOptions.ConfigurationKey).Bind(options));
var settings = builder.Config.GetSection(HangfireOptions.ConfigurationKey).Get<HangfireOptions>();
if (settings == null || settings.Enabled == false)
return;
// If there's no connection string, e.g. Umbraco hasn't been installed yet, skip as the composer still tries to register the jobs
var connectionString = builder.Config.GetConnectionString(settings.ConnectionStringName);
if (string.IsNullOrEmpty(connectionString))
return;
// Schedule the ImportBankHolidays method to run on the 1st of every month
RecurringJob.AddOrUpdate<BankHolidayImportTask>(
"import-bank-holidays",
x => x.ImportBankHolidays(),
Cron.Minutely());
}
}
(You might spot a couple of the Hangifre updates too!)Wiggy
05/14/2024, 12:16 PMcsharp
namespace Application.Core.OpeningHours.BankHolidays;
public class BankHolidayImportTask
{
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly IContentService _contentService;
private readonly IServerMessenger _serverMessenger;
private readonly IServiceProvider _serviceProvider;
public BankHolidayImportTask(
IUmbracoContextFactory umbracoContextFactory,
IContentService contentService,
IServiceProvider serviceProvider,
IServerMessenger serverMessenger)
{
_umbracoContextFactory = umbracoContextFactory;
_contentService = contentService;
_serverMessenger = serverMessenger;
_serviceProvider = serviceProvider;
}
public async Task ImportBankHolidays()
{
using var backgroundScope = new BackgroundScope(_serverMessenger);
using var _ = _umbracoContextFactory.EnsureUmbracoContext();
using var serviceScope = _serviceProvider.CreateScope();
var query = serviceScope.ServiceProvider.GetRequiredService<IPublishedContentQuery>();
var rootNode = query.ContentAtRoot().FirstOrDefault();
if (rootNode == null)
return;
// Do something with ContentService
var content = _contentService.GetById(rootNode.Id);
content.SetValue("phoneNumber", DateTime.Now.ToString());
_contentService.SaveAndPublish(content);
}
public class BackgroundScope : IDisposable
{
private readonly IServerMessenger _serverMessenger;
public BackgroundScope(IServerMessenger serverMessenger)
{
_serverMessenger = serverMessenger;
}
public void Dispose()
{
if (_serverMessenger is BatchedDatabaseServerMessenger batchedDatabaseServerMessenger)
{
batchedDatabaseServerMessenger.SendMessages();
}
}
}
}
Wiggy
05/14/2024, 12:17 PMSourceContext Umbraco.Cms.Infrastructure.HostedServices.QueuedHostedService
ThreadId 9
WorkItem workItem
System.AggregateException: One or more errors occurred. (No AmbientContext was found.)
---> System.InvalidOperationException: No AmbientContext was found.
at Umbraco.Cms.Infrastructure.Scoping.AmbientScopeContextStack.Pop()
at Umbraco.Cms.Infrastructure.Scoping.ScopeProvider.PopAmbientScopeContext()
at Umbraco.Cms.Infrastructure.Scoping.Scope.<>c__DisplayClass100_0.<RobustExit>g__HandleScopeContext|2()
at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions)
--- End of inner exception stack trace ---
at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions)
at Umbraco.Cms.Infrastructure.Scoping.Scope.RobustExit(Boolean completed, Boolean onException)
at Umbraco.Cms.Infrastructure.Scoping.Scope.DisposeLastScope()
at Umbraco.Cms.Infrastructure.Scoping.Scope.Dispose()
at Umbraco.Cms.Infrastructure.Examine.ExamineUmbracoIndexingHandler.DeferedReIndexForContent.<>c__DisplayClass6_0.<Execute>b__0(CancellationToken cancellationToken)
at Umbraco.Cms.Infrastructure.HostedServices.QueuedHostedService.BackgroundProcessing(CancellationToken stoppingToken)
Wiggy
05/14/2024, 12:19 PMSebastiaan
05/14/2024, 12:19 PMcs
var x = "test";
āļø
Tip: You can make it more readable with a language definition! (please? š )Sebastiaan
05/14/2024, 12:20 PMJemayn
05/14/2024, 12:25 PMcsharp
using var context = _umbracoContextFactory.EnsureUmbracoContext();
var rootNode = context.UmbracoContext.Content.GetAtRoot().FirstOrDefault();
if (rootNode == null)
return;
Sebastiaan
05/14/2024, 12:26 PMAddScoped
like in the sample code
cs
builder.Services.AddScoped<IJobs, Jobs>();
Instead of adding it as Transient
.Sebastiaan
05/14/2024, 12:27 PMJemayn
05/14/2024, 12:29 PMWiggy
05/14/2024, 12:30 PMSebastiaan
05/14/2024, 12:30 PMSebastiaan
05/14/2024, 12:30 PMSebastiaan
05/14/2024, 12:30 PMWiggy
05/14/2024, 12:31 PMSebastiaan
05/14/2024, 12:31 PMSebastiaan
05/14/2024, 12:31 PMWiggy
05/14/2024, 12:32 PMSebastiaan
05/14/2024, 12:32 PMWiggy
05/14/2024, 12:33 PMWiggy
05/14/2024, 12:33 PMWiggy
05/14/2024, 12:36 PMSystem.AggregateException: One or more errors occurred. (No AmbientContext was found.)
---> System.InvalidOperationException: No AmbientContext was found.
at Umbraco.Cms.Infrastructure.Scoping.AmbientScopeContextStack.Pop()
at Umbraco.Cms.Infrastructure.Scoping.ScopeProvider.PopAmbientScopeContext()
at Umbraco.Cms.Infrastructure.Scoping.Scope.<>c__DisplayClass100_0.<RobustExit>g__HandleScopeContext|2()
at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions)
--- End of inner exception stack trace ---
at Umbraco.Cms.Infrastructure.Scoping.Scope.TryFinally(Action[] actions)
at Umbraco.Cms.Infrastructure.Scoping.Scope.RobustExit(Boolean completed, Boolean onException)
at Umbraco.Cms.Infrastructure.Scoping.Scope.DisposeLastScope()
at Umbraco.Cms.Infrastructure.Scoping.Scope.Dispose()
at Umbraco.Cms.Infrastructure.Examine.ExamineUmbracoIndexingHandler.DeferedReIndexForContent.<>c__DisplayClass6_0.<Execute>b__0(CancellationToken cancellationToken)
at Umbraco.Cms.Infrastructure.HostedServices.QueuedHostedService.BackgroundProcessing(CancellationToken stoppingToken)
Sebastiaan
05/14/2024, 12:41 PMcs
public void ManipulateContent(PerformContext context)
{
using var backgroundScope = new BackgroundScope(_serverMessenger);
using var umbracoContext = _umbracoContextFactory.EnsureUmbracoContext();
using var serviceScope = _serviceProvider.CreateScope();
var rootNode = umbracoContext.UmbracoContext.Content?.GetAtRoot().FirstOrDefault();
if (rootNode == null) return;
Jemayn
05/14/2024, 12:42 PMSebastiaan
05/14/2024, 12:50 PMSebastiaan
05/14/2024, 1:03 PMSystem.InvalidOperationException: Cannot save a non-current version.
at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.DocumentRepository.PersistUpdatedItem(IContent entity)
at Umbraco.Cms.Core.Cache.DefaultRepositoryCachePolicy`2.Update(TEntity entity, Action`1 persistUpdated)
at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.EntityRepositoryBase`2.Save(TEntity entity)
at Umbraco.Cms.Core.Services.ContentService.<>c__DisplayClass64_0.<CommitDocumentChangesInternal>g__SaveDocument|2(IContent c)
at Umbraco.Cms.Core.Services.ContentService.CommitDocumentChangesInternal(ICoreScope scope, IContent content, EventMessages eventMessages, IReadOnlyCollection`1 allLangs, IDictionary`2 notificationState, Int32 userId, Boolean branchOne, Boolean branchRoot)
at Umbraco.Cms.Core.Services.ContentService.SaveAndPublish(IContent content, String culture, Int32 userId)
at v100test.BankHolidayImportTask.ImportBankHolidays() in E:\Dev\Temp\v100test\HangfireScheduler.cs:line 56
Which happens when the task runs when another update is still in progress. The code is now almost exactly the same as my packaged code..
The package code doesn't need this any more by the way: // Extra check whether Hangfire is enabled otherwise it will fail as the composer still tries to register the jobs
.
I've added the solution for you to fiddle with!
https://cdn.discordapp.com/attachments/1239907055725449297/1239926093197086750/v100test.zip?ex=6644b2a9&is=66436129&hm=aab4ed36b71589707cd3c7083a58cffb91bf6a038a777310dfa7ffd053f384b3&Sebastiaan
05/14/2024, 1:05 PMWiggy
05/14/2024, 1:11 PMSebastiaan
05/14/2024, 1:12 PM