diff --git a/MessagingService.BusinessLogic/Services/MessagingDomainService.cs b/MessagingService.BusinessLogic/Services/MessagingDomainService.cs index 439372e..fe99a28 100644 --- a/MessagingService.BusinessLogic/Services/MessagingDomainService.cs +++ b/MessagingService.BusinessLogic/Services/MessagingDomainService.cs @@ -117,29 +117,30 @@ public async Task> SendEmailMessage(EmailCommands.SendEmailCommand Result result = await ApplyEmailUpdates(async (EmailAggregate emailAggregate) => { // Check if this message has been sent before - if (emailAggregate.GetMessageStatus() != EmailMessageAggregate.MessageStatus.NotSet) - { + if (emailAggregate.GetMessageStatus() != EmailMessageAggregate.MessageStatus.NotSet) { return Result.Success(); } // send message to provider (record event) - emailAggregate.SendRequestToProvider(command.FromAddress, command.ToAddresses, command.Subject, command.Body, command.IsHtml, attachments); + Result stateResult = emailAggregate.SendRequestToProvider(command.FromAddress, command.ToAddresses, command.Subject, command.Body, command.IsHtml, attachments); + if (stateResult.IsFailed) + return stateResult; // Make call to Email provider here EmailServiceProxyResponse emailResponse = await this.EmailServiceProxy.SendEmail(command.MessageId, command.FromAddress, command.ToAddresses,command.Subject, command.Body, command.IsHtml, attachments, cancellationToken); - if (emailResponse.ApiCallSuccessful) - { + if (emailResponse.ApiCallSuccessful) { // response message from provider (record event) - emailAggregate.ReceiveResponseFromProvider(emailResponse.RequestIdentifier, - emailResponse.EmailIdentifier); + stateResult = emailAggregate.ReceiveResponseFromProvider(emailResponse.RequestIdentifier, emailResponse.EmailIdentifier); } - else - { - emailAggregate.ReceiveBadResponseFromProvider(emailResponse.Error, emailResponse.ErrorCode); + else { + stateResult = emailAggregate.ReceiveBadResponseFromProvider(emailResponse.Error, emailResponse.ErrorCode); } + if (stateResult.IsFailed) + return stateResult; + return Result.Success(); }, command.MessageId, cancellationToken, false); @@ -187,8 +188,10 @@ public async Task ResendEmailMessage(Guid connectionIdentifier, Result result = await ApplyEmailUpdates(async (EmailAggregate emailAggregate) => { // re-send message to provider (record event) - emailAggregate.ResendRequestToProvider(); - + Result stateResult = emailAggregate.ResendRequestToProvider(); + if (stateResult.IsFailed) + return stateResult; + // Make call to Email provider here EmailServiceProxyResponse emailResponse = await this.EmailServiceProxy.SendEmail(messageId, emailAggregate.FromAddress, @@ -198,16 +201,15 @@ await this.EmailServiceProxy.SendEmail(messageId, emailAggregate.FromAddress, emailAggregate.IsHtml, null, cancellationToken); - if (emailResponse.ApiCallSuccessful) - { + if (emailResponse.ApiCallSuccessful) { // response message from provider (record event) - emailAggregate.ReceiveResponseFromProvider(emailResponse.RequestIdentifier, - emailResponse.EmailIdentifier); + stateResult = emailAggregate.ReceiveResponseFromProvider(emailResponse.RequestIdentifier, emailResponse.EmailIdentifier); } - else - { - emailAggregate.ReceiveBadResponseFromProvider(emailResponse.Error, emailResponse.ErrorCode); + else { + stateResult = emailAggregate.ReceiveBadResponseFromProvider(emailResponse.Error, emailResponse.ErrorCode); } + if (stateResult.IsFailed) + return stateResult; return Result.Success(); }, messageId, cancellationToken); @@ -234,29 +236,35 @@ public async Task ResendSMSMessage(Guid connectionIdentifier, Guid messa public async Task UpdateMessageStatus(EmailCommands.UpdateMessageStatusCommand command, CancellationToken cancellationToken) { Result result = await ApplyEmailUpdates(async (EmailAggregate emailAggregate) => { + + Result stateResult; + switch (command.Status) { case EmailServices.MessageStatus.Bounced: - emailAggregate.MarkMessageAsBounced(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsBounced(command.Description, command.Timestamp); break; case EmailServices.MessageStatus.Delivered: - emailAggregate.MarkMessageAsDelivered(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsDelivered(command.Description, command.Timestamp); break; case EmailServices.MessageStatus.Failed: case EmailServices.MessageStatus.Unknown: - emailAggregate.MarkMessageAsFailed(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsFailed(command.Description, command.Timestamp); break; case EmailServices.MessageStatus.Rejected: - emailAggregate.MarkMessageAsRejected(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsRejected(command.Description, command.Timestamp); break; case EmailServices.MessageStatus.Spam: - emailAggregate.MarkMessageAsSpam(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsSpam(command.Description, command.Timestamp); break; default: // Unknown status - treat as failed - emailAggregate.MarkMessageAsFailed(command.Description, command.Timestamp); + stateResult = emailAggregate.MarkMessageAsFailed(command.Description, command.Timestamp); break; } + if (stateResult.IsFailed) + return stateResult; + return Result.Success(); }, command.MessageId, cancellationToken); return result; diff --git a/MessagingService.EmailAggregate.Tests/EmailAggregateTests.cs b/MessagingService.EmailAggregate.Tests/EmailAggregateTests.cs index c24f21d..7467404 100644 --- a/MessagingService.EmailAggregate.Tests/EmailAggregateTests.cs +++ b/MessagingService.EmailAggregate.Tests/EmailAggregateTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using SimpleResults; using Xunit; namespace MessagingService.EmailAggregate.Tests @@ -120,7 +121,9 @@ public void EmailAggregate_MarkMessageAsDelivered_IncorrectState_ErrorThrown(Mes } - Should.Throw(() => emailAggregate.MarkMessageAsDelivered(TestData.ProviderStatusDescription, TestData.DeliveredDateTime)); + Result result = emailAggregate.MarkMessageAsDelivered(TestData.ProviderStatusDescription, TestData.DeliveredDateTime); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -171,7 +174,9 @@ public void EmailAggregate_MarkMessageAsRejected_IncorrectState_ErrorThrown(Mess break; } - Should.Throw(() => emailAggregate.MarkMessageAsRejected(TestData.ProviderStatusDescription, TestData.RejectedDateTime)); + Result result = emailAggregate.MarkMessageAsRejected(TestData.ProviderStatusDescription, TestData.RejectedDateTime); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -222,7 +227,9 @@ public void EmailAggregate_MarkMessageAsFailed_IncorrectState_ErrorThrown(Messag break; } - Should.Throw(() => emailAggregate.MarkMessageAsFailed(TestData.ProviderStatusDescription, TestData.FailedDateTime)); + Result result = emailAggregate.MarkMessageAsFailed(TestData.ProviderStatusDescription, TestData.FailedDateTime); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -273,7 +280,9 @@ public void EmailAggregate_MarkMessageAsBounced_IncorrectState_ErrorThrown(Messa break; } - Should.Throw(() => emailAggregate.MarkMessageAsBounced(TestData.ProviderStatusDescription, TestData.BouncedDateTime)); + Result result = emailAggregate.MarkMessageAsBounced(TestData.ProviderStatusDescription, TestData.BouncedDateTime); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -324,7 +333,9 @@ public void EmailAggregate_MarkMessageAsSpam_IncorrectState_ErrorThrown(MessageS break; } - Should.Throw(() => emailAggregate.MarkMessageAsSpam(TestData.ProviderStatusDescription, TestData.SpamDateTime)); + Result result = emailAggregate.MarkMessageAsSpam(TestData.ProviderStatusDescription, TestData.SpamDateTime); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } @@ -358,7 +369,9 @@ public void EmailAggregate_ResendRequestToProvider_IsDelivered_MessageIsResent() public void EmailAggregate_ResendRequestToProvider_NotSet_ErrorThrown() { EmailAggregate emailAggregate = EmailAggregate.Create(TestData.MessageId); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -366,7 +379,9 @@ public void EmailAggregate_ResendRequestToProvider_InProgress_ErrorThrown() { EmailAggregate emailAggregate = EmailAggregate.Create(TestData.MessageId); emailAggregate.SendRequestToProvider(TestData.FromAddress, TestData.ToAddresses, TestData.Subject, TestData.Body, TestData.IsHtmlTrue, TestData.EmailAttachmentModels); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -376,7 +391,9 @@ public void EmailAggregate_ResendRequestToProvider_Rejected_ErrorThrown() { emailAggregate.SendRequestToProvider(TestData.FromAddress, TestData.ToAddresses, TestData.Subject, TestData.Body, TestData.IsHtmlTrue, TestData.EmailAttachmentModels); emailAggregate.ReceiveResponseFromProvider(TestData.ProviderRequestReference, TestData.ProviderEmailReference); emailAggregate.MarkMessageAsRejected(TestData.ProviderStatusDescription, TestData.RejectedDateTime); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -386,7 +403,9 @@ public void EmailAggregate_ResendRequestToProvider_Failed_ErrorThrown() { emailAggregate.SendRequestToProvider(TestData.FromAddress, TestData.ToAddresses, TestData.Subject, TestData.Body, TestData.IsHtmlTrue, TestData.EmailAttachmentModels); emailAggregate.ReceiveResponseFromProvider(TestData.ProviderRequestReference, TestData.ProviderEmailReference); emailAggregate.MarkMessageAsFailed(TestData.ProviderStatusDescription, TestData.FailedDateTime); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -396,7 +415,9 @@ public void EmailAggregate_ResendRequestToProvider_Spam_ErrorThrown() { emailAggregate.SendRequestToProvider(TestData.FromAddress, TestData.ToAddresses, TestData.Subject, TestData.Body, TestData.IsHtmlTrue, TestData.EmailAttachmentModels); emailAggregate.ReceiveResponseFromProvider(TestData.ProviderRequestReference, TestData.ProviderEmailReference); emailAggregate.MarkMessageAsSpam(TestData.ProviderStatusDescription, TestData.SpamDateTime); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -406,7 +427,9 @@ public void EmailAggregate_ResendRequestToProvider_Bounced_ErrorThrown() { emailAggregate.SendRequestToProvider(TestData.FromAddress, TestData.ToAddresses, TestData.Subject, TestData.Body, TestData.IsHtmlTrue, TestData.EmailAttachmentModels); emailAggregate.ReceiveResponseFromProvider(TestData.ProviderRequestReference, TestData.ProviderEmailReference); emailAggregate.MarkMessageAsBounced(TestData.ProviderStatusDescription, TestData.BouncedDateTime); - Should.Throw(() => emailAggregate.ResendRequestToProvider()); + Result result = emailAggregate.ResendRequestToProvider(); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] diff --git a/MessagingService.EmailMessageAggregate/EmailAggregate.cs b/MessagingService.EmailMessageAggregate/EmailAggregate.cs index a192c43..c8fffda 100644 --- a/MessagingService.EmailMessageAggregate/EmailAggregate.cs +++ b/MessagingService.EmailMessageAggregate/EmailAggregate.cs @@ -1,4 +1,6 @@ -namespace MessagingService.EmailMessageAggregate +using SimpleResults; + +namespace MessagingService.EmailMessageAggregate { using System; using System.Collections.Generic; @@ -12,81 +14,105 @@ using Shared.Logger; public static class EmailAggregateExtensions{ - public static void MarkMessageAsBounced(this EmailAggregate aggregate, String providerStatus, + public static Result MarkMessageAsBounced(this EmailAggregate aggregate, String providerStatus, DateTime bouncedDateTime) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] == MessageStatus.Bounced) - return; - aggregate.CheckMessageCanBeSetToBounced(); + return Result.Success(); + + Result result = aggregate.CheckMessageCanBeSetToBounced(); + if (result.IsFailed) + return result; EmailMessageBouncedEvent messageBouncedEvent = new(aggregate.AggregateId, providerStatus, bouncedDateTime); aggregate.ApplyAndAppend(messageBouncedEvent); + + return Result.Success(); } - public static void MarkMessageAsDelivered(this EmailAggregate aggregate, String providerStatus, - DateTime deliveredDateTime) + public static Result MarkMessageAsDelivered(this EmailAggregate aggregate, String providerStatus, + DateTime deliveredDateTime) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] == MessageStatus.Delivered) - return; - aggregate.CheckMessageCanBeSetToDelivered(); + return Result.Success(); + Result result = aggregate.CheckMessageCanBeSetToDelivered(); + if (result.IsFailed) + return result; EmailMessageDeliveredEvent messageDeliveredEvent = new(aggregate.AggregateId, providerStatus, deliveredDateTime); aggregate.ApplyAndAppend(messageDeliveredEvent); + + return Result.Success(); } - public static void MarkMessageAsFailed(this EmailAggregate aggregate, String providerStatus, + public static Result MarkMessageAsFailed(this EmailAggregate aggregate, String providerStatus, DateTime failedDateTime) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] == MessageStatus.Failed) - return; - aggregate.CheckMessageCanBeSetToFailed(); - + return Result.Success(); + var result = aggregate.CheckMessageCanBeSetToFailed(); + if (result.IsFailed) + return result; EmailMessageFailedEvent messageFailedEvent = new(aggregate.AggregateId, providerStatus, failedDateTime); aggregate.ApplyAndAppend(messageFailedEvent); + + return Result.Success(); } - public static void MarkMessageAsRejected(this EmailAggregate aggregate, String providerStatus, + public static Result MarkMessageAsRejected(this EmailAggregate aggregate, String providerStatus, DateTime rejectedDateTime) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] == MessageStatus.Rejected) - return; - aggregate.CheckMessageCanBeSetToRejected(); + return Result.Success(); + var result = aggregate.CheckMessageCanBeSetToRejected(); + if (result.IsFailed) + return result; EmailMessageRejectedEvent messageRejectedEvent = new(aggregate.AggregateId, providerStatus, rejectedDateTime); aggregate.ApplyAndAppend(messageRejectedEvent); + + return Result.Success(); } - public static void MarkMessageAsSpam(this EmailAggregate aggregate, String providerStatus, + public static Result MarkMessageAsSpam(this EmailAggregate aggregate, String providerStatus, DateTime spamDateTime) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] == MessageStatus.Spam) - return; - aggregate.CheckMessageCanBeSetToSpam(); + return Result.Success(); + var result = aggregate.CheckMessageCanBeSetToSpam(); + if (result.IsFailed) + return result; EmailMessageMarkedAsSpamEvent messageMarkedAsSpamEvent = new(aggregate.AggregateId, providerStatus, spamDateTime); aggregate.ApplyAndAppend(messageMarkedAsSpamEvent); + + return Result.Success(); } - public static void ReceiveResponseFromProvider(this EmailAggregate aggregate, String providerRequestReference, + public static Result ReceiveResponseFromProvider(this EmailAggregate aggregate, String providerRequestReference, String providerEmailReference) { ResponseReceivedFromEmailProviderEvent responseReceivedFromProviderEvent = new(aggregate.AggregateId, providerRequestReference, providerEmailReference); aggregate.ApplyAndAppend(responseReceivedFromProviderEvent); + + return Result.Success(); } - public static void ReceiveBadResponseFromProvider(this EmailAggregate aggregate, String error, String errorCode) + public static Result ReceiveBadResponseFromProvider(this EmailAggregate aggregate, String error, String errorCode) { BadResponseReceivedFromEmailProviderEvent badResponseReceivedFromProviderEvent = new(aggregate.AggregateId, errorCode, error); aggregate.ApplyAndAppend(badResponseReceivedFromProviderEvent); + + return Result.Success(); } public static MessageStatus GetMessageStatus(this EmailAggregate aggregate) @@ -94,7 +120,7 @@ public static MessageStatus GetMessageStatus(this EmailAggregate aggregate) return aggregate.DeliveryStatusList[aggregate.ResendCount]; } - public static void SendRequestToProvider(this EmailAggregate aggregate, String fromAddress, + public static Result SendRequestToProvider(this EmailAggregate aggregate, String fromAddress, List toAddresses, String subject, String body, @@ -114,59 +140,66 @@ public static void SendRequestToProvider(this EmailAggregate aggregate, String f (Int32)emailAttachment.FileType); aggregate.ApplyAndAppend(emailAttachmentRequestSentToProviderEvent); } + + return Result.Success(); } - public static void ResendRequestToProvider(this EmailAggregate aggregate) + public static Result ResendRequestToProvider(this EmailAggregate aggregate) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent && aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Delivered) { - throw new InvalidOperationException($"Cannot re-send a message to provider that has not already been sent. Current Status [{aggregate.DeliveryStatusList[aggregate.ResendCount]}]"); + return Result.Invalid($"Cannot re-send a message to provider that has not already been sent. Current Status [{aggregate.DeliveryStatusList[aggregate.ResendCount]}]"); } RequestResentToEmailProviderEvent requestResentToEmailProviderEvent = new(aggregate.AggregateId); aggregate.ApplyAndAppend(requestResentToEmailProviderEvent); + return Result.Success(); } - private static void CheckMessageCanBeSetToBounced(this EmailAggregate aggregate) + private static Result CheckMessageCanBeSetToBounced(this EmailAggregate aggregate) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) { - throw new InvalidOperationException($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to bounced"); + return Result.Invalid($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to bounced"); } + return Result.Success(); } - private static void CheckMessageCanBeSetToDelivered(this EmailAggregate aggregate) + private static Result CheckMessageCanBeSetToDelivered(this EmailAggregate aggregate) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) { - throw new InvalidOperationException($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to delivered"); + return Result.Invalid($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to delivered"); } + return Result.Success(); } - private static void CheckMessageCanBeSetToFailed(this EmailAggregate aggregate) - { - if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) - { - throw new InvalidOperationException($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to failed"); + private static Result CheckMessageCanBeSetToFailed(this EmailAggregate aggregate) { + if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) { + return Result.Invalid($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to failed"); } + + return Result.Success(); } - private static void CheckMessageCanBeSetToRejected(this EmailAggregate aggregate) + private static Result CheckMessageCanBeSetToRejected(this EmailAggregate aggregate) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) { - throw new InvalidOperationException($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to rejected"); + return Result.Invalid($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to rejected"); } + return Result.Success(); } - private static void CheckMessageCanBeSetToSpam(this EmailAggregate aggregate) + private static Result CheckMessageCanBeSetToSpam(this EmailAggregate aggregate) { if (aggregate.DeliveryStatusList[aggregate.ResendCount] != MessageStatus.Sent) { - throw new InvalidOperationException($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to spam"); + return Result.Invalid($"Message at status {aggregate.DeliveryStatusList[aggregate.ResendCount]} cannot be set to spam"); } + return Result.Success(); } public static void PlayEvent(this EmailAggregate aggregate, RequestSentToEmailProviderEvent domainEvent)