public HeadlessController(IUmbracoContextFactory context) { _context = context.EnsureUmbracoContext() ?? throw new Exception("UmbracoContext not found"); _searcher = ExamineSearchers.GetExternalIndexSearcher() ?? throw new Exception("ExternalIndex not found"); _contentMapper = new UmbracoContentMapper(Umbraco); _camelCasingSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }
public SiteRoot GetSiteRoot(int currentNodeId) { IPublishedContent node; using (UmbracoContextReference umbContextRef = _umbracoContextFactory.EnsureUmbracoContext()) { IPublishedContentCache contentCache = umbContextRef.UmbracoContext.Content; node = umbContextRef.UmbracoContext.Content.GetById(currentNodeId); } if (node == null) { _logger.Warn <CmsService>($"1.Node with id {currentNodeId} is null"); return(null); } var siteNode = node.AncestorsOrSelf().SingleOrDefault(x => x.ContentType.Alias == SiteRoot.ModelTypeAlias) as SiteRoot; if (siteNode == null) { _logger.Warn <CmsService>("siteNode is null"); } return(siteNode); }
public void Can_Lookup_Content() { var publishedSnapshot = new Mock <IPublishedSnapshot>(); publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of <IPublishedMemberCache>()); var content = new Mock <IPublishedContent>(); content.Setup(x => x.Id).Returns(2); IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of <IBackOfficeSecurityAccessor>(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of <IBackOfficeSecurity>()); var publishedSnapshotService = new Mock <IPublishedSnapshotService>(); IHostingEnvironment hostingEnvironment = Mock.Of <IHostingEnvironment>(); var globalSettings = new GlobalSettings(); var umbracoContextFactory = TestUmbracoContextFactory.Create(globalSettings, _umbracoContextAccessor); UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); IPublishedContentQuery publishedContentQuery = Mock.Of <IPublishedContentQuery>(query => query.Content(2) == content.Object); var ctrl = new TestSurfaceController(umbracoContextAccessor, publishedContentQuery, Mock.Of <IPublishedUrlProvider>()); var result = ctrl.GetContent(2) as PublishedContentResult; Assert.IsNotNull(result); Assert.IsNotNull(result.Content); Assert.AreEqual(2, result.Content.Id); }
public ErrorPageService(IUmbracoContextFactory contextFactory, IDomainService domainService, ILogger logger, Uri originalRequest = null) { _contextFactory = contextFactory; _domainService = domainService; _logger = logger; _contextReference = _contextFactory.EnsureUmbracoContext(); _originalRequest = originalRequest ?? _contextReference.UmbracoContext.HttpContext.Request.Url; }
public void Ensure_Image_Sources() { // setup a mock URL provider which we'll use for testing var mediaType = new PublishedContentType(Guid.NewGuid(), 777, "image", PublishedItemType.Media, Enumerable.Empty <string>(), Enumerable.Empty <PublishedPropertyType>(), ContentVariation.Nothing); var media = new Mock <IPublishedContent>(); media.Setup(x => x.ContentType).Returns(mediaType); var mediaUrlProvider = new Mock <IMediaUrlProvider>(); mediaUrlProvider.Setup(x => x.GetMediaUrl(It.IsAny <IPublishedContent>(), It.IsAny <string>(), It.IsAny <UrlMode>(), It.IsAny <string>(), It.IsAny <Uri>())) .Returns(UrlInfo.Url("/media/1001/my-image.jpg")); var umbracoContextAccessor = new TestUmbracoContextAccessor(); IUmbracoContextFactory umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); var webRoutingSettings = new WebRoutingSettings(); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, Options.Create(webRoutingSettings), new UrlProviderCollection(() => Enumerable.Empty <IUrlProvider>()), new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }), Mock.Of <IVariationContextAccessor>()); using (UmbracoContextReference reference = umbracoContextFactory.EnsureUmbracoContext()) { var mediaCache = Mock.Get(reference.UmbracoContext.Media); mediaCache.Setup(x => x.GetById(It.IsAny <Guid>())).Returns(media.Object); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); var result = imageSourceParser.EnsureImageSources(@"<p> <div> <img src="""" /> </div></p> <p> <div><img src="""" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div> </p> <p> <div><img src=""?width=100"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div> </p>"); Assert.AreEqual( @"<p> <div> <img src="""" /> </div></p> <p> <div><img src=""/media/1001/my-image.jpg"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div> </p> <p> <div><img src=""/media/1001/my-image.jpg?width=100"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div> </p>", result); } }
public ErrorPageService(IUmbracoContextFactory contextFactory, IDomainService domainService, ILocalizationService localizationService, ILogger logger, IVariationContextAccessor variationContextAccessor, Uri originalRequest = null) { _contextFactory = contextFactory; _domainService = domainService; _localizationService = localizationService; _logger = logger; _variantContextAccessor = variationContextAccessor; _contextReference = _contextFactory.EnsureUmbracoContext(); _originalRequest = originalRequest ?? _contextReference.UmbracoContext.HttpContext.Request.Url; }
public Website GetWebsiteById(int id) { Website website = null; using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext()) { website = umbracoContextReference.UmbracoContext.Content.GetById(id).AncestorOrSelf(Website.ModelTypeAlias) as Website; } return(website); }
public void ParseLocalLinks(string input, string result) { // setup a mock URL provider which we'll use for testing var contentUrlProvider = new Mock <IUrlProvider>(); contentUrlProvider .Setup(x => x.GetUrl(It.IsAny <IPublishedContent>(), It.IsAny <UrlMode>(), It.IsAny <string>(), It.IsAny <Uri>())) .Returns(UrlInfo.Url("/my-test-url")); var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty <string>(), Enumerable.Empty <PublishedPropertyType>(), ContentVariation.Nothing); var publishedContent = new Mock <IPublishedContent>(); publishedContent.Setup(x => x.Id).Returns(1234); publishedContent.Setup(x => x.ContentType).Returns(contentType); var mediaType = new PublishedContentType(Guid.NewGuid(), 777, "image", PublishedItemType.Media, Enumerable.Empty <string>(), Enumerable.Empty <PublishedPropertyType>(), ContentVariation.Nothing); var media = new Mock <IPublishedContent>(); media.Setup(x => x.ContentType).Returns(mediaType); var mediaUrlProvider = new Mock <IMediaUrlProvider>(); mediaUrlProvider.Setup(x => x.GetMediaUrl(It.IsAny <IPublishedContent>(), It.IsAny <string>(), It.IsAny <UrlMode>(), It.IsAny <string>(), It.IsAny <Uri>())) .Returns(UrlInfo.Url("/media/1001/my-image.jpg")); var umbracoContextAccessor = new TestUmbracoContextAccessor(); IUmbracoContextFactory umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); var webRoutingSettings = new WebRoutingSettings(); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, Microsoft.Extensions.Options.Options.Create(webRoutingSettings), new UrlProviderCollection(() => new[] { contentUrlProvider.Object }), new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }), Mock.Of <IVariationContextAccessor>()); using (UmbracoContextReference reference = umbracoContextFactory.EnsureUmbracoContext()) { var contentCache = Mock.Get(reference.UmbracoContext.Content); contentCache.Setup(x => x.GetById(It.IsAny <int>())).Returns(publishedContent.Object); contentCache.Setup(x => x.GetById(It.IsAny <Guid>())).Returns(publishedContent.Object); var mediaCache = Mock.Get(reference.UmbracoContext.Media); mediaCache.Setup(x => x.GetById(It.IsAny <int>())).Returns(media.Object); mediaCache.Setup(x => x.GetById(It.IsAny <Guid>())).Returns(media.Object); var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var output = linkParser.EnsureInternalLinks(input); Assert.AreEqual(result, output); } }
public void Migrate() { using (UmbracoContextReference umbracoContextReference = _context.EnsureUmbracoContext()) { using (var scope = _scopeProvider.CreateScope()) { var adminGroup = _userService.GetUserGroupByAlias(Constants.Security.AdminGroupAlias); adminGroup.AddAllowedSection("uiExamples"); _userService.Save(adminGroup); scope.Complete(); } } _logger.Info <AddSectionForAdmins>("Post migration completed"); }
/// <summary> /// Uses a Dictionary to store ALL the root nodes in cache. /// /// Uses the IDs in the Path property of the given node to get the Root node from the cached Dictionary. /// </summary> /// <param name="nodeId"></param> /// <returns></returns> public SiteRoot GetSiteRoot(int nodeId) { var cacheKey = CacheKey.Build <CmsServiceCachedProxy, Dictionary <int, SiteRoot> >("-1"); var sites = _cache.Get <Dictionary <int, SiteRoot> >(cacheKey); SiteRoot siteNode; if (sites != null) { // Use the IDs in the Path property to get the Root node from the cached Dictionary. IPublishedContent node; using (UmbracoContextReference umbContextRef = _umbracoContextFactory.EnsureUmbracoContext()) { var contentCache = umbContextRef.UmbracoContext.Content; node = umbContextRef.UmbracoContext.Content.GetById(nodeId); } var pathIds = node.Path.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Select(x => int.Parse(x)); foreach (var id in pathIds) { if (sites.ContainsKey(id)) { siteNode = sites[id]; return(siteNode); } } } // get here if there were no cached Site nodes, OR the Site node was not found in the dictionary sites = new Dictionary <int, SiteRoot>(); siteNode = _cmsService.GetSiteRoot(nodeId); if (siteNode != null) { // GetSiteNode might return null sites.Add(siteNode.Id, siteNode); } _cache.Add(cacheKey, sites); return(siteNode); }
public void Umbraco_Context_Not_Null() { var globalSettings = new GlobalSettings(); IHostingEnvironment hostingEnvironment = Mock.Of <IHostingEnvironment>(); IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of <IBackOfficeSecurityAccessor>(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of <IBackOfficeSecurity>()); var umbracoContextFactory = TestUmbracoContextFactory.Create(globalSettings, _umbracoContextAccessor); UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); IUmbracoContext umbCtx = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of <IPublishedContentQuery>(), Mock.Of <IPublishedUrlProvider>()); Assert.IsNotNull(ctrl.UmbracoContext); }
internal virtual DataRootElement LoadData() { var data = new DataRootElement(); using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext()) { var auctions = umbracoContextReference.UmbracoContext.Content.GetAtRoot().DescendantsOrSelfOfType(Umbraco.Web.PublishedModels.Auction.ModelTypeAlias) as IEnumerable <Umbraco.Web.PublishedModels.Auction>; data.Auctions = _mapper.MapEnumerable <Umbraco.Web.PublishedModels.Auction, Auction>(auctions); } long totalMembers; var members = _memberService.GetAll(1, 10000, out totalMembers); data.Members = _mapper.MapEnumerable <Umbraco.Core.Models.IMember, Member>(members); return(data); }
public void Can_Construct_And_Get_Result() { IHostingEnvironment hostingEnvironment = Mock.Of <IHostingEnvironment>(); IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of <IBackOfficeSecurityAccessor>(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of <IBackOfficeSecurity>()); var globalSettings = new GlobalSettings(); var umbracoContextFactory = TestUmbracoContextFactory.Create(globalSettings, _umbracoContextAccessor); UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of <IPublishedContentQuery>(), Mock.Of <IPublishedUrlProvider>()); IActionResult result = ctrl.Index(); Assert.IsNotNull(result); }
private static void AddMediaToBuilder(GeneratedSite entity, UmbracoContextReference umbracoContext, JobBuilder builder) { if (!string.IsNullOrEmpty(entity.MediaRootNodes)) { var mediaRoots = entity.MediaRootNodes.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); foreach (var mediaRoot in mediaRoots) { int mediaId; if (int.TryParse(mediaRoot, out mediaId)) { var rootMedia = umbracoContext.UmbracoContext.Media.GetById(mediaId); if (rootMedia != null) { builder.AddMediaWithDescendants(rootMedia); } } } } }
public void Mock_Current_Page() { var globalSettings = new GlobalSettings(); IHostingEnvironment hostingEnvironment = Mock.Of <IHostingEnvironment>(); IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of <IBackOfficeSecurityAccessor>(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of <IBackOfficeSecurity>()); var umbracoContextFactory = TestUmbracoContextFactory.Create(globalSettings, _umbracoContextAccessor); UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); IPublishedContent content = Mock.Of <IPublishedContent>(publishedContent => publishedContent.Id == 12345); var builder = new PublishedRequestBuilder(umbracoContext.CleanedUmbracoUrl, Mock.Of <IFileService>()); builder.SetPublishedContent(content); IPublishedRequest publishedRequest = builder.Build(); var routeDefinition = new UmbracoRouteValues(publishedRequest, null); var httpContext = new DefaultHttpContext(); httpContext.Features.Set(routeDefinition); var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of <IPublishedContentQuery>(), Mock.Of <IPublishedUrlProvider>()) { ControllerContext = new ControllerContext() { HttpContext = httpContext, RouteData = new RouteData() } }; var result = ctrl.GetContentFromCurrentPage() as PublishedContentResult; Assert.AreEqual(12345, result.Content.Id); }
private List <EnterspeedJob> GetJobsForContent(IContent content, UmbracoContextReference context) { var jobs = new List <EnterspeedJob>(); var culturesToPublish = new List <string>(); if (content.ContentType.VariesByCulture()) { culturesToPublish = content.PublishedCultures.ToList(); } else { var defaultCulture = GetDefaultCulture(context); if (content.Published) { culturesToPublish.Add(defaultCulture); } } var now = DateTime.UtcNow; foreach (var culture in culturesToPublish) { jobs.Add(new EnterspeedJob { ContentId = content.Id, Culture = culture, JobType = EnterspeedJobType.Publish, State = EnterspeedJobState.Pending, CreatedAt = now, UpdatedAt = now, }); } return(jobs); }
/// <inheritdoc/> public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // do not process if client-side request if (context.Request.IsClientSideRequest() && !_umbracoRequestOptions.Value.HandleAsServerSideRequest(context.Request)) { // we need this here because for bundle requests, these are 'client side' requests that we need to handle LazyInitializeBackOfficeServices(context.Request.Path); await next(context); return; } // Profiling start needs to be one of the first things that happens. // Also MiniProfiler.Current becomes null if it is handled by the event aggregator due to async/await _profiler?.UmbracoApplicationBeginRequest(context, _runtimeState.Level); _variationContextAccessor.VariationContext ??= new VariationContext(_defaultCultureAccessor.DefaultCulture); UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); Uri?currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request); _hostingEnvironment.EnsureApplicationMainUrl(currentApplicationUrl); var pathAndQuery = context.Request.GetEncodedPathAndQuery(); try { // Verbose log start of every request LogHttpRequest.TryGetCurrentHttpRequestId(out Guid? httpRequestId, _requestCache); _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, pathAndQuery); try { LazyInitializeBackOfficeServices(context.Request.Path); await _eventAggregator.PublishAsync(new UmbracoRequestBeginNotification(umbracoContextReference.UmbracoContext)); } catch (Exception ex) { // try catch so we don't kill everything in all requests _logger.LogError(ex.Message); } finally { try { await next(context); } finally { await _eventAggregator.PublishAsync(new UmbracoRequestEndNotification(umbracoContextReference.UmbracoContext)); } } } finally { // Verbose log end of every request (in v8 we didn't log the end request of ALL requests, only the front-end which was // strange since we always logged the beginning, so now we just log start/end of all requests) LogHttpRequest.TryGetCurrentHttpRequestId(out Guid? httpRequestId, _requestCache); _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); try { DisposeHttpContextItems(context.Request); } finally { // Dispose the umbraco context reference which will in turn dispose the UmbracoContext itself. umbracoContextReference.Dispose(); } } // Profiling end needs to be last of the first things that happens. // Also MiniProfiler.Current becomes null if it is handled by the event aggregator due to async/await _profiler?.UmbracoApplicationEndRequest(context, _runtimeState.Level); }
public override Task PerformExecuteAsync(object state) { if (Suspendable.ScheduledPublishing.CanRun == false) { return(Task.CompletedTask); } switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Subscriber: _logger.LogDebug("Does not run on subscriber servers."); return(Task.CompletedTask); case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); return(Task.CompletedTask); } // Ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { _logger.LogDebug("Does not run if not MainDom."); return(Task.CompletedTask); } // Do NOT run publishing if not properly running if (_runtimeState.Level != RuntimeLevel.Run) { _logger.LogDebug("Does not run if run level is not Run."); return(Task.CompletedTask); } try { // We don't need an explicit scope here because PerformScheduledPublish creates it's own scope // so it's safe as it will create it's own ambient scope. // Ensure we run with an UmbracoContext, because this will run in a background task, // and developers may be using the UmbracoContext in the event handlers. // TODO: or maybe not, CacheRefresherComponent already ensures a context when handling events // - UmbracoContext 'current' needs to be refactored and cleaned up // - batched messenger should not depend on a current HttpContext // but then what should be its "scope"? could we attach it to scopes? // - and we should definitively *not* have to flush it here (should be auto) using UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext(); try { // Run IEnumerable <PublishResult> result = _contentService.PerformScheduledPublish(DateTime.Now); foreach (IGrouping <PublishResultType, PublishResult> grouped in result.GroupBy(x => x.Result)) { _logger.LogInformation( "Scheduled publishing result: '{StatusCount}' items with status {Status}", grouped.Count(), grouped.Key); } } finally { // If running on a temp context, we have to flush the messenger if (contextReference.IsRoot) { _serverMessenger.SendMessages(); } } } catch (Exception ex) { // important to catch *everything* to ensure the task repeats _logger.LogError(ex, "Failed."); } return(Task.CompletedTask); }
/// <summary> /// Initializes a new instance of the <see cref="UmbracoJobActivatorScope"/> class. /// </summary> /// <param name="umbracoJobActivator">The umbraco job activator.</param> public UmbracoJobActivatorScope(UmbracoJobActivator umbracoJobActivator) { this.umbracoJobActivator = umbracoJobActivator; HttpContext.Current = new HttpContext(new SimpleWorkerRequest("/null.aspx", string.Empty, new StringWriter())); this.umracoContextReference = umbracoJobActivator.umbracoContextFactory.EnsureUmbracoContext(new HttpContextWrapper(HttpContext.Current)); }
private string GetDefaultCulture(UmbracoContextReference context) { return(context.UmbracoContext.Domains.DefaultCulture.ToLowerInvariant()); }
public override Task PerformExecuteAsync(object state) { if (Suspendable.ScheduledPublishing.CanRun == false) { return(Task.CompletedTask); } switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Subscriber: _logger.LogDebug("Does not run on subscriber servers."); return(Task.CompletedTask); case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); return(Task.CompletedTask); } // Ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { _logger.LogDebug("Does not run if not MainDom."); return(Task.CompletedTask); } // Do NOT run publishing if not properly running if (_runtimeState.Level != RuntimeLevel.Run) { _logger.LogDebug("Does not run if run level is not Run."); return(Task.CompletedTask); } try { // Ensure we run with an UmbracoContext, because this will run in a background task, // and developers may be using the UmbracoContext in the event handlers. // TODO: or maybe not, CacheRefresherComponent already ensures a context when handling events // - UmbracoContext 'current' needs to be refactored and cleaned up // - batched messenger should not depend on a current HttpContext // but then what should be its "scope"? could we attach it to scopes? // - and we should definitively *not* have to flush it here (should be auto) using UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext(); using IScope scope = _scopeProvider.CreateScope(autoComplete: true); /* We used to assume that there will never be two instances running concurrently where (IsMainDom && ServerRole == SchedulingPublisher) * However this is possible during an azure deployment slot swap for the SchedulingPublisher instance when trying to achieve zero downtime deployments. * If we take a distributed write lock, we are certain that the multiple instances of the job will not run in parallel. * It's possible that during the swapping process we may run this job more frequently than intended but this is not of great concern and it's * only until the old SchedulingPublisher shuts down. */ scope.EagerWriteLock(Constants.Locks.ScheduledPublishing); try { // Run IEnumerable <PublishResult> result = _contentService.PerformScheduledPublish(DateTime.Now); foreach (IGrouping <PublishResultType, PublishResult> grouped in result.GroupBy(x => x.Result)) { _logger.LogInformation( "Scheduled publishing result: '{StatusCount}' items with status {Status}", grouped.Count(), grouped.Key); } } finally { // If running on a temp context, we have to flush the messenger if (contextReference.IsRoot) { _serverMessenger.SendMessages(); } } } catch (Exception ex) { // important to catch *everything* to ensure the task repeats _logger.LogError(ex, "Failed."); } return(Task.CompletedTask); }