From 28b0ad3cc3f65130531a51bf305b96112afa506f Mon Sep 17 00:00:00 2001 From: "Atsuta, Ivan" Date: Mon, 8 Jun 2026 11:55:13 +0200 Subject: [PATCH] Framework.Subscriptions-to-async --- .../Events/DomainObjectEventMetadata.cs | 0 .../AutomationFrameworkSettings.cs | 1 - .../Services/ControllerEvaluator.cs | 6 +- .../NotificationEventDTO.cs | 14 ++-- .../ISubscriptionService.cs | 2 +- .../DomainObjectVersions.cs | 4 +- .../IMessageTemplate.cs | 3 +- .../ISubscription.cs | 16 ++--- .../RazorTemplate.cs | 10 ++- .../Subscription.cs | 37 ++++++---- .../EmployeeEmailExtractor.cs | 36 +++++----- .../IEmployeeEmailExtractor.cs | 3 +- .../INotificationExtractor.cs | 6 +- .../NotificationExtractor.cs | 67 ++++++++++--------- ...ficationMessageGenerationInfoExtensions.cs | 8 +-- .../SubscriptionService.cs | 47 ++++++++----- .../IDomainObjectModificationBLL.cs | 2 +- .../DomainObjectModificationBLL.cs | 18 +++-- .../Jobs/SendNotificationsJob.cs | 2 +- .../Impl/QueueService.cs | 3 +- .../Create/CountryCreateSubscription.cs | 4 +- .../Create/DateModelCreateSubscription.cs | 2 +- .../NotPersistentCustomModel/Subscription.cs | 33 ++++++--- .../Update/EmployeeUpdateSubscription.cs | 6 +- .../Attachment/AttachmentSubscription.cs | 6 +- .../AttachmentInlineSubscription.cs | 6 +- ...AttachmentTemplateEvaluatorSubscription.cs | 6 +- .../RazorInheritanceSubscription.cs | 4 +- .../RazorTemplateImplSubscription.cs | 4 +- .../NotificationCountryTests.cs | 1 - .../MetadataSubscriptionSystemServiceTests.cs | 48 ++++++------- .../Helpers/DataManager.Subscriptions.cs | 19 +++--- src/__SolutionItems/CommonAssemblyInfo.cs | 2 +- 33 files changed, 241 insertions(+), 185 deletions(-) rename src/Application/{Framework.Application.Runtime => Framework.Application.Abstractions}/Events/DomainObjectEventMetadata.cs (100%) diff --git a/src/Application/Framework.Application.Runtime/Events/DomainObjectEventMetadata.cs b/src/Application/Framework.Application.Abstractions/Events/DomainObjectEventMetadata.cs similarity index 100% rename from src/Application/Framework.Application.Runtime/Events/DomainObjectEventMetadata.cs rename to src/Application/Framework.Application.Abstractions/Events/DomainObjectEventMetadata.cs diff --git a/src/AutomationCore/Framework.AutomationCore/AutomationFrameworkSettings.cs b/src/AutomationCore/Framework.AutomationCore/AutomationFrameworkSettings.cs index 06da05c93..5a9fc3e56 100644 --- a/src/AutomationCore/Framework.AutomationCore/AutomationFrameworkSettings.cs +++ b/src/AutomationCore/Framework.AutomationCore/AutomationFrameworkSettings.cs @@ -18,4 +18,3 @@ public class AutomationFrameworkSettings public string[] LocalAdmins { get; set; } = []; } - diff --git a/src/AutomationCore/Framework.AutomationCore/Services/ControllerEvaluator.cs b/src/AutomationCore/Framework.AutomationCore/Services/ControllerEvaluator.cs index 6a238bbaf..195390d63 100644 --- a/src/AutomationCore/Framework.AutomationCore/Services/ControllerEvaluator.cs +++ b/src/AutomationCore/Framework.AutomationCore/Services/ControllerEvaluator.cs @@ -47,7 +47,11 @@ private async Task InternalEvaluateAsync(LambdaExpression invokeExpr, Func { await using var scope = rootServiceProvider.CreateAsyncScope(); - var c = new DefaultHttpContext { RequestServices = scope.ServiceProvider }; + var c = new DefaultHttpContext + { + RequestServices = scope.ServiceProvider, + RequestAborted = scope.ServiceProvider.GetService()?.CancellationToken ?? CancellationToken.None + }; await new WebApiInvoker(c, context => InvokeController(context, func)) .WithMiddleware(next => new ImpersonateMiddleware(next), (middleware, httpContext) => middleware.Invoke(httpContext, customUserCredential)) diff --git a/src/Notification/Framework.Notification.DTO/NotificationEventDTO.cs b/src/Notification/Framework.Notification.DTO/NotificationEventDTO.cs index 5b2d27e51..582a86b60 100644 --- a/src/Notification/Framework.Notification.DTO/NotificationEventDTO.cs +++ b/src/Notification/Framework.Notification.DTO/NotificationEventDTO.cs @@ -8,25 +8,25 @@ namespace Framework.Notification.DTO; public class NotificationEventDTO { [DataMember] - public List Recipients { get; set; } + public List Recipients { get; set; } = []; [DataMember] - public List Attachments { get; set; } + public List Attachments { get; set; } = []; [DataMember] - public string From { get; set; } + public string From { get; set; } = null!; [DataMember] - public string FromName { get; set; } + public string FromName { get; set; } = null!; [DataMember] - public string Subject { get; set; } + public string Subject { get; set; } = null!; [DataMember] - public NotificationMessage Message { get; set; } + public NotificationMessage Message { get; set; } = null!; [DataMember] - public NotificationTechnicalInformationDTO TechnicalInformation { get; set; } + public NotificationTechnicalInformationDTO TechnicalInformation { get; set; } = null!; public NotificationEventDTO() { diff --git a/src/Subscriptions/Framework.Subscriptions.Abstractions/ISubscriptionService.cs b/src/Subscriptions/Framework.Subscriptions.Abstractions/ISubscriptionService.cs index 78996e14f..8a34d7522 100644 --- a/src/Subscriptions/Framework.Subscriptions.Abstractions/ISubscriptionService.cs +++ b/src/Subscriptions/Framework.Subscriptions.Abstractions/ISubscriptionService.cs @@ -5,6 +5,6 @@ namespace Framework.Subscriptions; public interface ISubscriptionService { - IEnumerable> Process(DomainObjectVersions versions); + IAsyncEnumerable> ProcessAsync(DomainObjectVersions versions); } diff --git a/src/Subscriptions/Framework.Subscriptions.Domain/DomainObjectVersions.cs b/src/Subscriptions/Framework.Subscriptions.Domain/DomainObjectVersions.cs index 51649440c..d6b050aea 100644 --- a/src/Subscriptions/Framework.Subscriptions.Domain/DomainObjectVersions.cs +++ b/src/Subscriptions/Framework.Subscriptions.Domain/DomainObjectVersions.cs @@ -33,8 +33,8 @@ public record DomainObjectVersions(TDomainObject? Previous, TDoma /// public override string ToString() => $"DomainObjectType: {this.DomainObjectType}, Previous: {this.Previous}, Current: {this.Current}"; - public DomainObjectVersions ChangeDomainObject(Func selector) - where TNewDomainObject : class => new(this.Previous == null ? null : selector(this.Previous), this.Current == null ? null : selector(this.Current)); + public async ValueTask> ChangeDomainObjectAsync(Func> selector) + where TNewDomainObject : class => new(this.Previous == null ? null : await selector(this.Previous), this.Current == null ? null : await selector(this.Current)); private static DomainObjectChangeType GetChangeType(TDomainObject? previous, TDomainObject? current) { diff --git a/src/Subscriptions/Framework.Subscriptions.Metadata/IMessageTemplate.cs b/src/Subscriptions/Framework.Subscriptions.Metadata/IMessageTemplate.cs index cbf4bdb91..1d3dbecc6 100644 --- a/src/Subscriptions/Framework.Subscriptions.Metadata/IMessageTemplate.cs +++ b/src/Subscriptions/Framework.Subscriptions.Metadata/IMessageTemplate.cs @@ -5,6 +5,5 @@ namespace Framework.Subscriptions.Metadata; public interface IMessageTemplate where TRenderingObject : class { - (string Subject, string Body) Render(IServiceProvider serviceProvider, DomainObjectVersions versions); + ValueTask<(string Subject, string Body)> Render(IServiceProvider serviceProvider, DomainObjectVersions versions, CancellationToken ct); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Metadata/ISubscription.cs b/src/Subscriptions/Framework.Subscriptions.Metadata/ISubscription.cs index 2b3d429d7..3064d56eb 100644 --- a/src/Subscriptions/Framework.Subscriptions.Metadata/ISubscription.cs +++ b/src/Subscriptions/Framework.Subscriptions.Metadata/ISubscription.cs @@ -16,21 +16,21 @@ public interface ISubscription : ISubscription Type ISubscription.RenderingObjectType => typeof(TRenderingObject); - bool IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions versions); + ValueTask IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions versions, CancellationToken ct); - TRenderingObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject); + ValueTask ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct); - IEnumerable> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions); + IAsyncEnumerable> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions); - IEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions); + IAsyncEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions); - IEnumerable> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions versions); + IAsyncEnumerable> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions versions); - IEnumerable GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions versions); + IAsyncEnumerable GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions versions); - (string Subject, string Body) GetMessage(IServiceProvider serviceProvider, DomainObjectVersions versions); + ValueTask<(string Subject, string Body)> GetMessage(IServiceProvider serviceProvider, DomainObjectVersions versions, CancellationToken ct); - IEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions); + IAsyncEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions); } /// diff --git a/src/Subscriptions/Framework.Subscriptions.Metadata/RazorTemplate.cs b/src/Subscriptions/Framework.Subscriptions.Metadata/RazorTemplate.cs index c801df226..a6816b7ab 100644 --- a/src/Subscriptions/Framework.Subscriptions.Metadata/RazorTemplate.cs +++ b/src/Subscriptions/Framework.Subscriptions.Metadata/RazorTemplate.cs @@ -43,15 +43,19 @@ public abstract partial class RazorTemplate : IMessageTemplate public abstract string Subject { get; } - public (string Subject, string Body) Render(IServiceProvider serviceProvider, DomainObjectVersions versions) + public ValueTask<(string Subject, string Body)> Render( + IServiceProvider serviceProvider, + DomainObjectVersions versions, + CancellationToken ct) { + ct.ThrowIfCancellationRequested(); + this.state = new RenderingState(new StringWriter(), serviceProvider, versions); this.Execute(); - return (this.Subject, this.State.Writer.ToString()); + return new((this.Subject, this.State.Writer.ToString())); } protected record RenderingState(StringWriter Writer, IServiceProvider ServiceProvider, DomainObjectVersions Versions); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Metadata/Subscription.cs b/src/Subscriptions/Framework.Subscriptions.Metadata/Subscription.cs index 6f9c56f0e..4fc7692b8 100644 --- a/src/Subscriptions/Framework.Subscriptions.Metadata/Subscription.cs +++ b/src/Subscriptions/Framework.Subscriptions.Metadata/Subscription.cs @@ -11,12 +11,11 @@ namespace Framework.Subscriptions.Metadata; - public abstract class Subscription : Subscription where TDomainObject : class where TMessageTemplate : IMessageTemplate { - public sealed override TDomainObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject) => domainObject; + public sealed override ValueTask ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct) => new(domainObject); } public abstract class Subscription : ISubscription @@ -40,22 +39,34 @@ public abstract class Subscription SecurityRoles { get; } = []; - public (string Subject, string Body) GetMessage(IServiceProvider serviceProvider, DomainObjectVersions versions) => - serviceProvider.GetRequiredService().Create().Render(serviceProvider, versions); + public ValueTask<(string Subject, string Body)> GetMessage( + IServiceProvider serviceProvider, + DomainObjectVersions versions, + CancellationToken ct) => + serviceProvider.GetRequiredService().Create().Render(serviceProvider, versions, ct); - public abstract TRenderingObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject); + public abstract ValueTask ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct); - public virtual bool IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions versions) => true; + public virtual ValueTask IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions versions, CancellationToken ct) => + new(true); - public virtual IEnumerable> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions) => []; + public virtual IAsyncEnumerable> GetTo( + IServiceProvider serviceProvider, + DomainObjectVersions versions) => AsyncEnumerable.Empty>(); - public virtual IEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) => []; + public virtual IAsyncEnumerable> GetCopyTo( + IServiceProvider serviceProvider, + DomainObjectVersions versions) => AsyncEnumerable.Empty>(); - public virtual IEnumerable> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) => - []; + public virtual IAsyncEnumerable> GetReplyTo( + IServiceProvider serviceProvider, + DomainObjectVersions versions) => + AsyncEnumerable.Empty>(); - public virtual IEnumerable GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions versions) => []; + public virtual IAsyncEnumerable GetNotificationFilterGroups( + IServiceProvider serviceProvider, + DomainObjectVersions versions) => AsyncEnumerable.Empty(); - public virtual IEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) => []; + public virtual IAsyncEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) => + AsyncEnumerable.Empty(); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/EmployeeEmailExtractor.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/EmployeeEmailExtractor.cs index 74b64d0bf..4af2fa712 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/EmployeeEmailExtractor.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/EmployeeEmailExtractor.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.Runtime.CompilerServices; using Anch.Core; using Anch.GenericQueryable; @@ -15,23 +16,28 @@ public class EmployeeEmailExtractor( IVisualIdentityInfo principalVisualIdentityInfo, IVisualIdentityInfo employeeVisualIdentityInfo, IQueryableSource queryableSource, - EmployeeInfo employeeInfo, - IDefaultCancellationTokenSource? defaultCancellationTokenSource = null) : IEmployeeEmailExtractor + EmployeeInfo employeeInfo) : IEmployeeEmailExtractor where TEmployee : class { - public ImmutableHashSet GetEmails(ImmutableArray securityRoles, ImmutableArray notificationFilterGroups) => + public IAsyncEnumerable GetEmails(ImmutableArray securityRoles, ImmutableArray notificationFilterGroups) => + this.GetEmailsInternal(securityRoles, notificationFilterGroups); - defaultCancellationTokenSource.RunSync(async ct => - { - var principalNames = await notificationPrincipalExtractor.GetPrincipalsAsync(securityRoles, notificationFilterGroups) - .Select(principalVisualIdentityInfo.Name.Getter) - .ToHashSetAsync(null, ct); + private async IAsyncEnumerable GetEmailsInternal( + ImmutableArray securityRoles, + ImmutableArray notificationFilterGroups, + [EnumeratorCancellation] CancellationToken ct = default) + { + var principalNames = await notificationPrincipalExtractor.GetPrincipalsAsync(securityRoles, notificationFilterGroups) + .Select(principalVisualIdentityInfo.Name.Getter) + .ToHashSetAsync(null, ct); - return await queryableSource.GetQueryable() - .Where(employeeVisualIdentityInfo.Name.Path.Select(employeeName => principalNames.Contains(employeeName))) - .Select(employeeInfo.Email.Path) - .GenericAsAsyncEnumerable() - .ToImmutableHashSetAsync(ct); - }); + await foreach (var email in queryableSource.GetQueryable() + .Where(employeeVisualIdentityInfo.Name.Path.Select(employeeName => principalNames.Contains(employeeName))) + .Select(employeeInfo.Email.Path) + .GenericAsAsyncEnumerable() + .WithCancellation(ct)) + { + yield return email; + } + } } - diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/IEmployeeEmailExtractor.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/IEmployeeEmailExtractor.cs index a81ff23a9..a9fa559c7 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/IEmployeeEmailExtractor.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/IEmployeeEmailExtractor.cs @@ -7,6 +7,5 @@ namespace Framework.Subscriptions; public interface IEmployeeEmailExtractor { - ImmutableHashSet GetEmails(ImmutableArray securityRoles, ImmutableArray notificationFilterGroups); + IAsyncEnumerable GetEmails(ImmutableArray securityRoles, ImmutableArray notificationFilterGroups); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/INotificationExtractor.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/INotificationExtractor.cs index 15141f584..244b0edc2 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/INotificationExtractor.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/INotificationExtractor.cs @@ -2,8 +2,8 @@ namespace Framework.Subscriptions; -public interface INotificationExtractor +public interface INotificationExtractor + where TDomainObject : class { - IEnumerable GetNotifications(DomainObjectVersions versions); + IAsyncEnumerable GetNotifications(DomainObjectVersions versions); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationExtractor.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationExtractor.cs index 9fe7be5b6..ce9958881 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationExtractor.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationExtractor.cs @@ -1,5 +1,5 @@ -using System.Collections.Immutable; -using System.Net.Mail; +using System.Net.Mail; +using System.Runtime.CompilerServices; using Anch.Core; using Anch.IdentitySource; @@ -15,49 +15,48 @@ public class NotificationExtractor( IServiceProvider serviceProvider, IIdentityInfoSource identityInfoSource, ISubscription subscription, - IEmployeeEmailExtractor employeeEmailExtractor) : INotificationExtractor + IEmployeeEmailExtractor employeeEmailExtractor) : INotificationExtractor where TDomainObject : class where TRenderingObject : class { - public IEnumerable GetNotifications(DomainObjectVersions versions) + public IAsyncEnumerable GetNotifications(DomainObjectVersions versions) { - var typedVersions = (DomainObjectVersions)versions; - var technicalInformation = new NotificationTechnicalInformation( subscription.MessageTemplateCode, typeof(TDomainObject).FullName!, identityInfoSource.TryGetIdentityInfo() - .Maybe(identityInfo => identityInfo.GetId(typedVersions.Previous ?? typedVersions.Current!) as Guid?)); + .Maybe(identityInfo => identityInfo.GetId(versions.Previous ?? versions.Current!) as Guid?)); - return from mailMessage in this.GetMailMessages(typedVersions) + return from mailMessage in this.GetMailMessages(versions) select new Notification.Domain.Notification(technicalInformation, mailMessage); } - private IEnumerable GetMailMessages(DomainObjectVersions versions) + private async IAsyncEnumerable GetMailMessages(DomainObjectVersions versions, [EnumeratorCancellation] CancellationToken ct = default) { - if (subscription.IsProcessed(serviceProvider, versions)) + if (await subscription.IsProcessed(serviceProvider, versions, ct)) { var preTo = subscription.GetTo(serviceProvider, versions); - var authTo = this.GetAuthTo(versions); + var authTo = this.GetAuthTo(versions, ct); var resultTo = this.GetMergeResult(preTo, authTo); var copyTo = subscription.GetCopyTo(serviceProvider, versions); var replyTo = subscription.GetReplyTo(serviceProvider, versions); - return ReGroup(resultTo, copyTo, replyTo).Select(this.ToMailMessage); - } - else - { - return []; + await foreach (var mailMessage in ReGroup(resultTo, copyTo, replyTo).Select(this.ToMailMessage).WithCancellation(ct)) + { + yield return mailMessage; + } } } - private MailMessage ToMailMessage(NotificationMessageGenerationInfo notificationMessageGenerationInfo) + private async ValueTask ToMailMessage( + NotificationMessageGenerationInfo notificationMessageGenerationInfo, + CancellationToken ct) { - var (subject, body) = subscription.GetMessage(serviceProvider, notificationMessageGenerationInfo.Versions); + var (subject, body) = await subscription.GetMessage(serviceProvider, notificationMessageGenerationInfo.Versions, ct); - var attachments = subscription.GetAttachments(serviceProvider, notificationMessageGenerationInfo.Versions); + var attachments = await subscription.GetAttachments(serviceProvider, notificationMessageGenerationInfo.Versions).ToImmutableArrayAsync(ct); var mailMessage = new MailMessage { @@ -80,30 +79,33 @@ private MailMessage ToMailMessage(NotificationMessageGenerationInfo> ReGroup( - IEnumerable> to, - IEnumerable> copyTo, - IEnumerable> replyTo) => + private static IAsyncEnumerable> ReGroup( + IAsyncEnumerable> to, + IAsyncEnumerable> copyTo, + IAsyncEnumerable> replyTo) => - from g in new[] { to.GroupRecipients(RecipientRole.To), copyTo.GroupRecipients(RecipientRole.Copy), replyTo.GroupRecipients(RecipientRole.ReplyTo) }.RegroupRecipients() + from g in new[] { to.GroupRecipients(RecipientRole.To), copyTo.GroupRecipients(RecipientRole.Copy), replyTo.GroupRecipients(RecipientRole.ReplyTo) } + .ToAsyncEnumerable().RegroupRecipients() let recipients = g.Select(pair => new NotificationRecipient(pair.Recipient, pair.Tag)) select new NotificationMessageGenerationInfo([.. recipients], g.Key); - private IEnumerable> GetAuthTo(DomainObjectVersions versions) + private async IAsyncEnumerable> GetAuthTo( + DomainObjectVersions versions, + [EnumeratorCancellation] CancellationToken ct = default) { if (subscription.SecurityRoles.Length > 0) { - var notificationFilterGroups = subscription.GetNotificationFilterGroups(serviceProvider, versions).ToImmutableArray(); + var notificationFilterGroups = await subscription.GetNotificationFilterGroups(serviceProvider, versions).ToImmutableArrayAsync(ct); if (notificationFilterGroups.Length > 0) { - var emails = employeeEmailExtractor.GetEmails(subscription.SecurityRoles, notificationFilterGroups); + var emails = await employeeEmailExtractor.GetEmails(subscription.SecurityRoles, notificationFilterGroups).ToImmutableHashSetAsync(ct); if (emails.Count > 0) { - var renderingVersions = versions.ChangeDomainObject(domainObject => subscription.ConvertToRenderingObject(serviceProvider, domainObject)); + var renderingVersions = await versions.ChangeDomainObjectAsync(domainObject => subscription.ConvertToRenderingObject(serviceProvider, domainObject, ct)); yield return new NotificationMessageGenerationInfo(emails, renderingVersions); } @@ -111,11 +113,11 @@ private IEnumerable> GetAuth } } - private IEnumerable> GetMergeResult( - IEnumerable> preTo, - IEnumerable> authTo) => + private IAsyncEnumerable> GetMergeResult( + IAsyncEnumerable> preTo, + IAsyncEnumerable> authTo) => - from g in new[] { preTo.GroupRecipients(false), authTo.GroupRecipients(true) }.RegroupRecipients() + from g in new[] { preTo.GroupRecipients(false), authTo.GroupRecipients(true) }.ToAsyncEnumerable().RegroupRecipients() let resultRecipients = g.Partial( pair => pair.Tag, @@ -125,4 +127,3 @@ private IEnumerable> GetMerg select new NotificationMessageGenerationInfo([.. resultRecipients], g.Key); } - diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationMessageGenerationInfoExtensions.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationMessageGenerationInfoExtensions.cs index a7e54f049..97c10d26d 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationMessageGenerationInfoExtensions.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/NotificationMessageGenerationInfoExtensions.cs @@ -5,8 +5,8 @@ namespace Framework.Subscriptions; public static class NotificationMessageGenerationInfoExtensions { - public static IEnumerable, (TRecipient Recipient, TTag Tag)>> - GroupRecipients(this IEnumerable> source, TTag tag) + public static IAsyncEnumerable, (TRecipient Recipient, TTag Tag)>> + GroupRecipients(this IAsyncEnumerable> source, TTag tag) where TRenderingObject : class => @@ -17,9 +17,9 @@ from recipient in item.Recipients group (recipient, tag) by item.Versions; - public static IEnumerable, TValue>> + public static IAsyncEnumerable, TValue>> RegroupRecipients( - this IEnumerable, TValue>>> source) + this IAsyncEnumerable, TValue>>> source) where TRenderingObject : class => diff --git a/src/Subscriptions/Framework.Subscriptions.Runtime/SubscriptionService.cs b/src/Subscriptions/Framework.Subscriptions.Runtime/SubscriptionService.cs index b533abcde..5c360d467 100644 --- a/src/Subscriptions/Framework.Subscriptions.Runtime/SubscriptionService.cs +++ b/src/Subscriptions/Framework.Subscriptions.Runtime/SubscriptionService.cs @@ -2,33 +2,46 @@ using Framework.Core; using Framework.Subscriptions.Domain; +using Framework.Subscriptions.Metadata; namespace Framework.Subscriptions; public class SubscriptionService( IServiceProxyFactory serviceProxyFactory, ISubscriptionResolver subscriptionResolver, - IMessageSender notificationMessageSender, - IDefaultCancellationTokenSource? defaultCancellationTokenSource) : ISubscriptionService + IMessageSender notificationMessageSender) : ISubscriptionService { - public IEnumerable> Process(DomainObjectVersions versions) - { - foreach (var subscription in subscriptionResolver.Resolve(versions.DomainObjectType, versions.ChangeType)) - { - yield return TryResult.Catch(() => - { - var notificationExtractorType = typeof(NotificationExtractor<,>).MakeGenericType(subscription.DomainObjectType, subscription.RenderingObjectType); + public IAsyncEnumerable> ProcessAsync(DomainObjectVersions versions) => + subscriptionResolver.Resolve(versions.DomainObjectType, versions.ChangeType) + .ToAsyncEnumerable() + .Select(async (ISubscription subscription, CancellationToken ct) => + { + try + { + await new Func, DomainObjectVersions, CancellationToken, Task>(this.ProcessAsync) + .CreateGenericMethod(subscription.DomainObjectType, subscription.RenderingObjectType) + .Invoke>(subscription, versions, ct); - var notificationExtractor = serviceProxyFactory.Create(notificationExtractorType, subscription); + return TryResult.Return(subscription.Header); + } + catch (Exception ex) + { + return TryResult.CreateFault(ex); + } + }); - foreach (var notification in notificationExtractor.GetNotifications(versions)) - { - defaultCancellationTokenSource.RunSync(async ct => await notificationMessageSender.SendAsync(notification, ct)); - } + private async Task ProcessAsync( + ISubscription subscription, + DomainObjectVersions versions, + CancellationToken ct) + where TDomainObject : class + where TRenderingObject : class + { + var notificationExtractor = serviceProxyFactory.Create>(subscription); - return subscription.Header; - }); + await foreach (var notification in notificationExtractor.GetNotifications(versions).WithCancellation(ct)) + { + await notificationMessageSender.SendAsync(notification, ct); } } } - diff --git a/src/_Configuration/Framework.Configuration.BLL.Core/IDomainObjectModificationBLL.cs b/src/_Configuration/Framework.Configuration.BLL.Core/IDomainObjectModificationBLL.cs index 284336d7b..04d1280b2 100644 --- a/src/_Configuration/Framework.Configuration.BLL.Core/IDomainObjectModificationBLL.cs +++ b/src/_Configuration/Framework.Configuration.BLL.Core/IDomainObjectModificationBLL.cs @@ -10,7 +10,7 @@ public partial interface IDomainObjectModificationBLL /// /// Ограничение на количество обработанных модификаций /// Количество обработанных модификаций - ITryResult Process(int limit = 1000); + Task> ProcessAsync(int limit = 1000, CancellationToken ct = default); /// /// Получение состояния обработки очереди diff --git a/src/_Configuration/Framework.Configuration.BLL/DomainObjectModificationBLL.cs b/src/_Configuration/Framework.Configuration.BLL/DomainObjectModificationBLL.cs index f632d6a28..90ab00fc7 100644 --- a/src/_Configuration/Framework.Configuration.BLL/DomainObjectModificationBLL.cs +++ b/src/_Configuration/Framework.Configuration.BLL/DomainObjectModificationBLL.cs @@ -1,4 +1,5 @@ -using Anch.SecuritySystem.Providers; +using Anch.GenericQueryable; +using Anch.SecuritySystem.Providers; using Framework.Configuration.Domain; using Framework.Core; @@ -19,12 +20,17 @@ public partial class DomainObjectModificationBLL( IDomainObjectVersionsResolverFactory domainObjectVersionsResolverFactory) : SecurityDomainBLLBase(context, securityProvider) { - public ITryResult Process(int limit = 1000) + public async Task> ProcessAsync(int limit, CancellationToken ct) { - this.Context.NamedLockService.LockAsync(ConfigurationNamedLock.ProcessModifications, LockRole.Update).GetAwaiter().GetResult(); + await this.Context.NamedLockService.LockAsync(ConfigurationNamedLock.ProcessModifications, LockRole.Update, ct); - var modifications = this.Context.Logics.DomainObjectModification.GetUnsecureQueryable().Where(m => !m.Processed) // Add Order by time? - .Take(limit).ToList(); + var modifications = await this.Context + .Logics + .DomainObjectModification + .GetUnsecureQueryable() + .Where(m => !m.Processed) // Add Order by time? + .Take(limit) + .GenericToListAsync(ct); logger.LogDebug("Found {Count} modifications", modifications.Count); @@ -42,7 +48,7 @@ public ITryResult Process(int limit = 1000) var versions = this.GetDomainObjectVersions(info); - foreach (var tryResult in subscriptionService.Process(versions)) + await foreach (var tryResult in subscriptionService.ProcessAsync(versions).WithCancellation(ct)) { tryResult.Match( _ => { }, diff --git a/src/_Configuration/Framework.Configuration.BLL/Jobs/SendNotificationsJob.cs b/src/_Configuration/Framework.Configuration.BLL/Jobs/SendNotificationsJob.cs index ff3a41e7a..1f7c8b8a5 100644 --- a/src/_Configuration/Framework.Configuration.BLL/Jobs/SendNotificationsJob.cs +++ b/src/_Configuration/Framework.Configuration.BLL/Jobs/SendNotificationsJob.cs @@ -3,5 +3,5 @@ public class SendNotificationsJob(IConfigurationBLLContext context) : ISendNotificationsJob { - public async Task ExecuteAsync(CancellationToken cancellationToken) => context.Logics.DomainObjectModification.Process(); + public Task ExecuteAsync(CancellationToken cancellationToken) => context.Logics.DomainObjectModification.ProcessAsync(1000, cancellationToken); } diff --git a/src/_Configuration/Framework.Configuration.WebApi/Impl/QueueService.cs b/src/_Configuration/Framework.Configuration.WebApi/Impl/QueueService.cs index d03c0f00d..a2b9b664f 100644 --- a/src/_Configuration/Framework.Configuration.WebApi/Impl/QueueService.cs +++ b/src/_Configuration/Framework.Configuration.WebApi/Impl/QueueService.cs @@ -18,10 +18,9 @@ public int ProcessModifications(int limit) DBSessionMode.Write, context => { - context.Authorization.SecuritySystem.CheckAccessAsync(SecurityRole.SystemIntegration, this.HttpContext.RequestAborted).GetAwaiter().GetResult(); - return context.Logics.DomainObjectModification.Process(limit == 0 ? 1000 : limit); + return context.Logics.DomainObjectModification.ProcessAsync(limit == 0 ? 1000 : limit, this.HttpContext.RequestAborted).GetAwaiter().GetResult(); }); return result.Match(v => v, ex => throw ex); diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Country/Create/CountryCreateSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Country/Create/CountryCreateSubscription.cs index 49abbb3e1..66667306f 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Country/Create/CountryCreateSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Country/Create/CountryCreateSubscription.cs @@ -14,12 +14,12 @@ public class CountryCreateSubscription : Subscription> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DataModel/Create/DateModelCreateSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DataModel/Create/DateModelCreateSubscription.cs index 1651906b6..b3c566356 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DataModel/Create/DateModelCreateSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DataModel/Create/DateModelCreateSubscription.cs @@ -15,7 +15,7 @@ public class DateModelCreateSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DomainChangedByRecipients/NotPersistentCustomModel/Subscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DomainChangedByRecipients/NotPersistentCustomModel/Subscription.cs index c5eb8cef6..7beabe242 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DomainChangedByRecipients/NotPersistentCustomModel/Subscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/DomainChangedByRecipients/NotPersistentCustomModel/Subscription.cs @@ -1,4 +1,5 @@ using System.Net.Mail; +using System.Runtime.CompilerServices; using System.Text; using Framework.Subscriptions.Domain; @@ -15,25 +16,35 @@ public class Subscription : Subscription ConvertToRenderingObject( IServiceProvider serviceProvider, - Domain.Directories.Country domainObject) => new(serviceProvider, domainObject); + Domain.Directories.Country domainObject, + CancellationToken ct) => new(serviceProvider, domainObject); - public override IEnumerable> GetTo( + public override IAsyncEnumerable> GetTo( IServiceProvider serviceProvider, - DomainObjectVersions versions) - { - yield return new("tester@luxoft.com", versions.ChangeDomainObject(c => this.ConvertToRenderingObject(serviceProvider, c))); - } + DomainObjectVersions versions) => + + new[] { "tester@luxoft.com" } + .ToAsyncEnumerable() + .Select(async (email, ct) => + new NotificationMessageGenerationInfo( + email, + await versions.ChangeDomainObjectAsync(c => this.ConvertToRenderingObject(serviceProvider, c, ct)))); + + public override IAsyncEnumerable> GetReplyTo( + IServiceProvider serviceProvider, + DomainObjectVersions versions) => this.InternalGetReplyTo(serviceProvider, versions); - public override IEnumerable> GetReplyTo( + private async IAsyncEnumerable> InternalGetReplyTo( IServiceProvider serviceProvider, - DomainObjectVersions versions) + DomainObjectVersions versions, + [EnumeratorCancellation] CancellationToken ct = default) { - yield return new("replayTo@luxoft.com", versions.ChangeDomainObject(c => this.ConvertToRenderingObject(serviceProvider, c))); + yield return new("replayTo@luxoft.com", await versions.ChangeDomainObjectAsync(c => this.ConvertToRenderingObject(serviceProvider, c, ct))); } - public override IEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) { yield return new(new MemoryStream(Encoding.UTF8.GetBytes("Hello world!")), AttachmentName); } diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Employee/Update/EmployeeUpdateSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Employee/Update/EmployeeUpdateSubscription.cs index bff1a7af5..8925f9053 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Employee/Update/EmployeeUpdateSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Employee/Update/EmployeeUpdateSubscription.cs @@ -14,17 +14,17 @@ public class EmployeeUpdateSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetReplyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetReplyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("replayTo@luxoft.com", versions); } diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/Attachment/AttachmentSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/Attachment/AttachmentSubscription.cs index 3a94e41cc..3970b7610 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/Attachment/AttachmentSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/Attachment/AttachmentSubscription.cs @@ -14,17 +14,17 @@ public class AttachmentSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable GetAttachments(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable GetAttachments(IServiceProvider _, DomainObjectVersions versions) { yield return new System.Net.Mail.Attachment(new MemoryStream(Encoding.UTF8.GetBytes("Hello world!")), AttachmentName) { diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentInline/AttachmentInlineSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentInline/AttachmentInlineSubscription.cs index f7d0fd43c..5bb1493a5 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentInline/AttachmentInlineSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentInline/AttachmentInlineSubscription.cs @@ -14,17 +14,17 @@ public class AttachmentInlineSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable GetAttachments(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable GetAttachments(IServiceProvider _, DomainObjectVersions versions) { yield return new(new MemoryStream(Encoding.UTF8.GetBytes("Hello world!")), AttachmentName) { diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentTemplateEvaluator/AttachmentTemplateEvaluatorSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentTemplateEvaluator/AttachmentTemplateEvaluatorSubscription.cs index 4fca90f2f..c54c1222c 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentTemplateEvaluator/AttachmentTemplateEvaluatorSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/AttachmentTemplateEvaluator/AttachmentTemplateEvaluatorSubscription.cs @@ -14,17 +14,17 @@ public class AttachmentTemplateEvaluatorSubscription : Subscription> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider serviceProvider, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) + public override async IAsyncEnumerable GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions versions) { var template = Encoding.UTF8.GetBytes($"Hello world! {versions.Current!.NameNative}"); diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerInheritance/RazorInheritanceSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerInheritance/RazorInheritanceSubscription.cs index 70b60777c..38916a127 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerInheritance/RazorInheritanceSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerInheritance/RazorInheritanceSubscription.cs @@ -14,12 +14,12 @@ public class RazorInheritanceSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } diff --git a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerTemplateImpl/RazorTemplateImplSubscription.cs b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerTemplateImpl/RazorTemplateImplSubscription.cs index 4b06dfafc..3423e2676 100644 --- a/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerTemplateImpl/RazorTemplateImplSubscription.cs +++ b/src/_SampleSystem/SampleSystem.Subscriptions.Metadata/Examples/RazerTemplateImpl/RazorTemplateImplSubscription.cs @@ -14,12 +14,12 @@ public class RazorTemplateImplSubscription : Subscription> GetTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } - public override IEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) + public override async IAsyncEnumerable> GetCopyTo(IServiceProvider _, DomainObjectVersions versions) { yield return new("tester@luxoft.com", versions); } diff --git a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/NotificationCountryTests.cs b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/NotificationCountryTests.cs index 125d26f67..5392c9ba3 100644 --- a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/NotificationCountryTests.cs +++ b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/NotificationCountryTests.cs @@ -145,4 +145,3 @@ public void EmulateFailureCountryModification_RaisedException() Assert.Equal("Both arguments (previous and current) can't be null", argumentException.Message); } } - diff --git a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/Subscriptions_Metadata/MetadataSubscriptionSystemServiceTests.cs b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/Subscriptions_Metadata/MetadataSubscriptionSystemServiceTests.cs index 725109dca..189bd84d8 100644 --- a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/Subscriptions_Metadata/MetadataSubscriptionSystemServiceTests.cs +++ b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/Subscriptions_Metadata/MetadataSubscriptionSystemServiceTests.cs @@ -1,5 +1,7 @@ using System.Text; +using Anch.Testing.Xunit; + using Framework.Core; using Framework.Notification.Domain; @@ -13,14 +15,14 @@ public sealed class MetadataSubscriptionSystemServiceTests(IServiceProvider root { protected override async ValueTask InitializeAsync(CancellationToken ct) => this.GetNotifications().Clear(); - [Fact] - public void SubscriptionFromMetadataShouldBeSent() + [AnchFact] + public async Task SubscriptionFromMetadataShouldBeSent(CancellationToken ct) { // Arrange var employee = this.CreateEmployee(); // Act - var results = this.DataManager.ProcessSubscription(employee, employee); + var results = await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var errors = results.GetErrors().ToList(); var expectedNotifications = this.GetNotifications() @@ -32,15 +34,15 @@ public void SubscriptionFromMetadataShouldBeSent() Assert.Equal("replayTo@luxoft.com", Assert.Single(notification.Recipients, z => z.Type == RecipientRole.ReplyTo).Name); } - [Fact] - public void RazorTemplateImpl_SubscriptionFromMetadataShouldBeSent() + [AnchFact] + public async Task RazorTemplateImpl_SubscriptionFromMetadataShouldBeSent(CancellationToken ct) { // Arrange var employee = this.DataManager.SaveEmployee("Chuck Norris"); var message = @"String.Concat it is good choice for Chuck Norris."; // Act - var results = this.DataManager.ProcessSubscription(employee, employee); + var results = await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var errors = results.GetErrors().ToList(); var expectedNotifications = this.GetNotifications() @@ -53,18 +55,18 @@ public void RazorTemplateImpl_SubscriptionFromMetadataShouldBeSent() Assert.Empty(errors); var notification = Assert.Single(expectedNotifications); Assert.Equal(message, notification.Message.Message); - Assert.False(notification.Recipients.Any(z => z.Type == RecipientRole.ReplyTo)); + Assert.DoesNotContain(notification.Recipients, z => z.Type == RecipientRole.ReplyTo); } - [Fact] - public void LocalRazorTemplate_SubscriptionFromMetadataShouldBeSent() + [AnchFact] + public async Task LocalRazorTemplate_SubscriptionFromMetadataShouldBeSent(CancellationToken ct) { // Arrange var employee = this.CreateEmployee(); var message = $"

Hi there!!!

{Environment.NewLine}My test employee Name: John Doe {Environment.NewLine}Date: 21 Oct 2015"; // Act - var results = this.DataManager.ProcessSubscription(employee, employee); + var results = await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var errors = results.GetErrors().ToList(); var expectedNotifications = this.GetNotifications() @@ -80,15 +82,15 @@ public void LocalRazorTemplate_SubscriptionFromMetadataShouldBeSent() /// IADFRAME-1525 Сделать пример использования аттачей в CodeFirst подписках ///
/// Создать тест: подписка с аттачем, который добавляется в нотификацию - [Fact] - public void AttachTest() + [AnchFact] + public async Task AttachTest(CancellationToken ct) { // Arrange var employee = this.CreateEmployee(); var content = Encoding.UTF8.GetBytes("Hello world!"); // Act - this.DataManager.ProcessSubscription(employee, employee); + await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var expectedNotifications = this.GetNotifications() .Where(n => n.From == "Attachment@luxoft.com"); @@ -97,22 +99,22 @@ public void AttachTest() var notification = expectedNotifications.Single(); var attachment = notification.Attachments.Single(); Assert.Equal(content, attachment.Content); - Assert.Equal(SampleSystem.Subscriptions.Metadata.Examples.Attachment.AttachmentSubscription.AttachmentName, attachment.Name); + Assert.Equal(Subscriptions.Metadata.Examples.Attachment.AttachmentSubscription.AttachmentName, attachment.Name); } /// /// IADFRAME-1525 Сделать пример использования аттачей в CodeFirst подписках /// /// Создать тест: подписка с аттачем который провернут через шаблонизатор (TemplateEvaluatorFactory) просто текст, который добавляется в нотификацию - [Fact] - public void AttachTemplateEvaluatorTest() + [AnchFact] + public async Task AttachTemplateEvaluatorTest(CancellationToken ct) { // Arrange var employee = this.CreateEmployee(); var content = "Hello world! John Doe "; // Act - this.DataManager.ProcessSubscription(employee, employee); + await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var expectedNotifications = this.GetNotifications().Where(n => n.From == "AttachmentTemplateEvaluator@luxoft.com"); @@ -127,15 +129,15 @@ public void AttachTemplateEvaluatorTest() /// IADFRAME-1525 Сделать пример использования аттачей в CodeFirst подписках /// /// Создать тест: подписка с inline аттачем (ContentId), который добавляется в нотификацию - [Fact] - public void AttachInlinedTest() + [AnchFact] + public async Task AttachInlinedTest(CancellationToken ct) { // Arrange var employee = this.CreateEmployee(); var messageTemplate = @" John Doe
"; // Act - this.DataManager.ProcessSubscription(employee, employee); + await this.DataManager.ProcessSubscriptionAsync(employee, employee, ct); var expectedNotifications = this.GetNotifications() .Where(n => n.From == "InlineAttach@luxoft.com"); @@ -147,13 +149,13 @@ public void AttachInlinedTest() Assert.Single(notification.Attachments); } - [Fact] - public void DateModelCreateSubscriptionTest() + [AnchFact] + public async Task DateModelCreateSubscriptionTest(CancellationToken ct) { // Arrange // Act - this.DataManager.ProcessSubscription(null, new DateModel { Year = 2019 }); + await this.DataManager.ProcessSubscriptionAsync(null, new DateModel { Year = 2019 }, ct); var expectedNotifications = this.GetNotifications() .Where(n => n.From == "DateModelCreateSampleSystem@luxoft.com"); diff --git a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/_Environment/TestData/Helpers/DataManager.Subscriptions.cs b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/_Environment/TestData/Helpers/DataManager.Subscriptions.cs index fbcad639e..68c5c4717 100644 --- a/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/_Environment/TestData/Helpers/DataManager.Subscriptions.cs +++ b/src/_SampleSystem/_Tests/SampleSystem.IntegrationTests.NHibernate/_Environment/TestData/Helpers/DataManager.Subscriptions.cs @@ -1,5 +1,7 @@ -using Framework.AutomationCore.RootServiceProviderContainer; +using Framework.Application; +using Framework.AutomationCore.RootServiceProviderContainer; using Framework.Core; +using Framework.Database; using Framework.Subscriptions; using Framework.Subscriptions.Domain; @@ -9,15 +11,16 @@ namespace SampleSystem.IntegrationTests._Environment.TestData.Helpers; public partial class DataManager { - public List> ProcessSubscription(T? prev, T? next) + public Task>> ProcessSubscriptionAsync(T? prev, T? next, CancellationToken ct) where T : class => - this.EvaluateWrite(context => - { - var subscriptionService = context.ServiceProvider.GetRequiredService(); + this.EvaluateAsync( + DBSessionMode.Write, + async context => + { + var subscriptionService = context.ServiceProvider.GetRequiredService(); - return subscriptionService.Process(new DomainObjectVersions(prev, next)).ToList(); - }); + return await subscriptionService.ProcessAsync(new DomainObjectVersions(prev, next)).ToListAsync(ct); + }); } - diff --git a/src/__SolutionItems/CommonAssemblyInfo.cs b/src/__SolutionItems/CommonAssemblyInfo.cs index 5c43eea0f..f479ceb71 100644 --- a/src/__SolutionItems/CommonAssemblyInfo.cs +++ b/src/__SolutionItems/CommonAssemblyInfo.cs @@ -4,7 +4,7 @@ [assembly: AssemblyCompany("Luxoft")] [assembly: AssemblyCopyright("Copyright © Luxoft 2009-2026")] -[assembly: AssemblyVersion("27.2.10.0")] +[assembly: AssemblyVersion("27.3.0.0")] #if DEBUG [assembly: AssemblyConfiguration("Debug")]