public static async Task Run( [ServiceBusTrigger("%cms-messages-topic%", "%cms-messages-subscription%", Connection = "service-bus-connection-string")] Message sitefinityMessage, [Inject] IMessageProcessor messageProcessor, [Inject] IMessagePropertiesService messagePropertiesService, ILogger log) { if (sitefinityMessage == null) { throw new ArgumentNullException(nameof(sitefinityMessage)); } sitefinityMessage.UserProperties.TryGetValue("ActionType", out var actionType); sitefinityMessage.UserProperties.TryGetValue("CType", out var contentType); sitefinityMessage.UserProperties.TryGetValue("Id", out var messageContentId); // logger should allow setting up correlation id and should be picked up from message log.LogInformation($"{nameof(SitefinityMessageHandler)}: Received message action '{actionType}' for type '{contentType}' with Id: '{messageContentId}': Correlation id {sitefinityMessage.CorrelationId}"); var message = Encoding.UTF8.GetString(sitefinityMessage?.Body); if (string.IsNullOrWhiteSpace(message)) { throw new ArgumentException("Message cannot be null or empty.", nameof(sitefinityMessage)); } if (!Enum.IsDefined(typeof(MessageAction), actionType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(actionType), $"Invalid message action '{actionType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageAction)))}'"); } if (!Enum.IsDefined(typeof(MessageContentType), contentType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(contentType), $"Invalid message content type '{contentType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageContentType)))}'"); } var messageAction = Enum.Parse <MessageAction>(actionType?.ToString()); var messageContentType = Enum.Parse <MessageContentType>(contentType?.ToString()); var sequenceNumber = messagePropertiesService.GetSequenceNumber(sitefinityMessage); var result = await messageProcessor.ProcessAsync(message, sequenceNumber, messageContentType, messageAction).ConfigureAwait(false); switch (result) { case HttpStatusCode.OK: log.LogInformation($"{ClassFullName}: Content Page Id: {messageContentId}: Updated Content Page"); break; case HttpStatusCode.Created: log.LogInformation($"{ClassFullName}: Content Page Id: {messageContentId}: Created Content Page"); break; case HttpStatusCode.AlreadyReported: log.LogInformation($"{ClassFullName}: Content Page Id: {messageContentId}: Content Page previously updated"); break; default: log.LogWarning($"{ClassFullName}: Content Page Id: {messageContentId}: Content Page not Posted: Status: {result}"); break; } }
public async Task Process(Message sitefinityMessage) { if (sitefinityMessage == null) { throw new ArgumentNullException(nameof(sitefinityMessage)); } sitefinityMessage.UserProperties.TryGetValue(MessageProperty.Action, out var messagePropertyActionType); sitefinityMessage.UserProperties.TryGetValue(MessageProperty.ContentType, out var messagePropertyContentType); sitefinityMessage.UserProperties.TryGetValue(MessageProperty.JobProfileId, out var messageContentId); var messageBody = Encoding.UTF8.GetString(sitefinityMessage?.Body); if (string.IsNullOrWhiteSpace(messageBody)) { throw new ArgumentException("Message cannot be null or empty.", nameof(sitefinityMessage)); } if (!Enum.IsDefined(typeof(MessageActionType), messagePropertyActionType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(messagePropertyActionType), $"Invalid message action '{messagePropertyActionType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageActionType)))}'"); } if (!Enum.IsDefined(typeof(MessageContentType), messagePropertyContentType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(messagePropertyContentType), $"Invalid message content type '{messagePropertyContentType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageContentType)))}'"); } var messageAction = Enum.Parse <MessageActionType>(messagePropertyActionType?.ToString()); var messageContentType = Enum.Parse <MessageContentType>(messagePropertyContentType?.ToString()); var sequenceNumber = messagePropertiesService.GetSequenceNumber(sitefinityMessage); var result = await messageProcessor.ProcessAsync(messageBody, sequenceNumber, messageContentType, messageAction).ConfigureAwait(false); switch (result) { case HttpStatusCode.OK: logger.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Updated segment"); break; case HttpStatusCode.Created: logger.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Created segment"); break; case HttpStatusCode.AlreadyReported: logger.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Segment previously updated"); break; default: logger.LogWarning($"{ClassFullName}: JobProfile Id: {messageContentId}: Segment not Posted: Status: {result}"); break; } }
public async Task MessageHandlerReturnsSuccessForSegmentUpdated(HttpStatusCode expectedResult) { // arrange const MessageAction messageAction = MessageAction.Published; const MessageContentType messageContentType = MessageContentType.Pages; const long sequenceNumber = 123; var model = A.Fake <ContentPageMessage>(); var message = JsonConvert.SerializeObject(model); var serviceBusMessage = new Message(Encoding.ASCII.GetBytes(message)); serviceBusMessage.UserProperties.Add("ActionType", messageAction); serviceBusMessage.UserProperties.Add("CType", messageContentType); serviceBusMessage.UserProperties.Add("Id", Guid.NewGuid()); A.CallTo(() => messagePropertiesService.GetSequenceNumber(serviceBusMessage)).Returns(sequenceNumber); A.CallTo(() => messageProcessor.ProcessAsync(message, sequenceNumber, messageContentType, messageAction)).Returns(expectedResult); // act await MessageHandler.Run(serviceBusMessage, messageProcessor, messagePropertiesService, logger).ConfigureAwait(false); // assert A.CallTo(() => messagePropertiesService.GetSequenceNumber(serviceBusMessage)).MustHaveHappenedOnceExactly(); A.CallTo(() => messageProcessor.ProcessAsync(message, sequenceNumber, messageContentType, messageAction)).MustHaveHappenedOnceExactly(); }
public async Task Run([ServiceBusTrigger("%cms-messages-topic%", "%cms-messages-subscription%", Connection = "service-bus-connection-string")] Message sitefinityMessage) { if (sitefinityMessage == null) { throw new ArgumentNullException(nameof(sitefinityMessage)); } correlationIdProvider.CorrelationId = sitefinityMessage.CorrelationId; sitefinityMessage.UserProperties.TryGetValue("ActionType", out var actionType); sitefinityMessage.UserProperties.TryGetValue("CType", out var contentType); sitefinityMessage.UserProperties.TryGetValue("Id", out var messageContentId); // logger should allow setting up correlation id and should be picked up from message logService.LogInformation($"{nameof(SitefinityMessageHandler)}: Received message action '{actionType}' for type '{contentType}' with Id: '{messageContentId}': Correlation id {sitefinityMessage.CorrelationId}"); var message = Encoding.UTF8.GetString(sitefinityMessage?.Body); if (string.IsNullOrWhiteSpace(message)) { throw new ArgumentException("Message cannot be null or empty.", nameof(sitefinityMessage)); } if (!Enum.IsDefined(typeof(MessageAction), actionType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(actionType), $"Invalid message action '{actionType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageAction)))}'"); } if (contentType.ToString().Contains("-", StringComparison.OrdinalIgnoreCase)) { var contentTypeString = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(contentType.ToString()); contentType = contentTypeString.Replace("-", string.Empty, true, CultureInfo.InvariantCulture); } if (!Enum.IsDefined(typeof(MessageContentType), contentType?.ToString())) { throw new ArgumentOutOfRangeException(nameof(contentType), $"Invalid message content type '{contentType}' received, should be one of '{string.Join(",", Enum.GetNames(typeof(MessageContentType)))}'"); } var messageAction = Enum.Parse <MessageAction>(actionType?.ToString()); var messageContentType = Enum.Parse <MessageContentType>(contentType?.ToString()); var sequenceNumber = messagePropertiesService.GetSequenceNumber(sitefinityMessage); var result = await messageProcessor.ProcessAsync(message, sequenceNumber, messageContentType, messageAction).ConfigureAwait(false); switch (result) { case HttpStatusCode.OK: logService.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Updated segment"); break; case HttpStatusCode.Created: logService.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Created segment"); break; case HttpStatusCode.AlreadyReported: logService.LogInformation($"{ClassFullName}: JobProfile Id: {messageContentId}: Segment previously updated"); break; case HttpStatusCode.Accepted: logService.LogWarning($"{ClassFullName}: JobProfile Id: {messageContentId}: Upserted segment, but Apprenticeship/Course refresh failed"); break; default: logService.LogWarning($"{ClassFullName}: JobProfile Id: {messageContentId}: Segment not Posted: Status: {result}"); break; } }