Exemplo n.º 1
0
        /// <inheritdoc/>
        public async Task <IList <NotificationResponse> > ResendNotifications(string applicationName, string[] notificationIds, NotificationType notifType = NotificationType.Mail, bool ignoreAlreadySent = false)
        {
            this.logger.TraceInformation($"Started {nameof(this.ResendNotifications)} method of {nameof(EmailHandlerManager)}.");
            if (string.IsNullOrWhiteSpace(applicationName))
            {
                throw new ArgumentException("Application Name cannot be null or empty.", nameof(applicationName));
            }

            if (notificationIds is null)
            {
                throw new ArgumentNullException(nameof(notificationIds));
            }

            IList <NotificationResponse> notificationResponses = new List <NotificationResponse>();

            // Queue a single cloud message for all entities created to enable parallel processing.
            var            cloudQueue    = this.cloudStorageClient.GetCloudQueue(this.notificationQueue);
            IList <string> cloudMessages = BusinessUtilities.GetCloudMessagesForIds(applicationName, notificationIds, notifType, ignoreAlreadySent);

            await this.cloudStorageClient.QueueCloudMessages(cloudQueue, cloudMessages).ConfigureAwait(false);

            notificationIds.ToList().ForEach(id =>
            {
                notificationResponses.Add(new NotificationResponse()
                {
                    NotificationId = id,
                    Status         = NotificationItemStatus.Queued,
                });
            });
            this.logger.TraceInformation($"Finished {nameof(this.ResendNotifications)} method of {nameof(EmailHandlerManager)}.");
            return(notificationResponses);
        }
        public ActionResult Index(DrinksViewModel model)
        {
            if (ModelState.IsValid)
            {
                if (model.SelectedDrink != null)
                {
                    var selectedDrink = _context.GetCachedDrinks().FirstOrDefault(x => x.ID == model.SelectedDrink);
                    var updatedStocks = BusinessUtilities.UpdateStocksByDrinkPurchased(_context.GetCachedStocks(), selectedDrink);

                    foreach (var stock in updatedStocks)
                    {
                        _context.AddOrUpdateStock(stock);
                    }

                    model.IsSubmitSuccessful = true;

                    _context.AddOrderHistory
                    (
                        new OrderHistory()
                    {
                        DrinkName = selectedDrink.Name,
                        OrderTime = DateTime.Now
                    }
                    );
                }

                model.AvailableDrinks = BusinessUtilities.FilterDrinksByStocks(_context.GetCachedDrinks(), _context.GetCachedStocks());
            }

            return(View(model));
        }
        public ActionResult Index()
        {
            var availableDrinks = BusinessUtilities.FilterDrinksByStocks(_context.GetCachedDrinks(), _context.GetCachedStocks());

            var drinksViewModel = new DrinksViewModel()
            {
                AvailableDrinks    = availableDrinks,
                IsSubmitSuccessful = false
            };

            return(View(drinksViewModel));
        }
Exemplo n.º 4
0
        /// <inheritdoc/>
        public async Task <IList <NotificationResponse> > QueueEmailNotifications(string applicationName, EmailNotificationItem[] emailNotificationItems)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var  traceProps = new Dictionary <string, string>();
            bool result     = false;

            try
            {
                this.logger.TraceInformation($"Started {nameof(this.QueueEmailNotifications)} method of {nameof(EmailHandlerManager)}.", traceProps);
                if (string.IsNullOrWhiteSpace(applicationName))
                {
                    throw new ArgumentException("Application Name cannot be null or empty.", nameof(applicationName));
                }

                if (emailNotificationItems is null)
                {
                    throw new ArgumentNullException(nameof(emailNotificationItems));
                }

                traceProps[AIConstants.Application]            = applicationName;
                traceProps[AIConstants.EmailNotificationCount] = emailNotificationItems.Length.ToString(CultureInfo.InvariantCulture);

                this.logger.WriteCustomEvent("QueueEmailNotifications Started", traceProps);
                IList <NotificationResponse>        notificationResponses    = new List <NotificationResponse>();
                IList <EmailNotificationItemEntity> notificationItemEntities = await this.emailManager.CreateNotificationEntities(applicationName, emailNotificationItems, NotificationItemStatus.Queued).ConfigureAwait(false);

                List <List <EmailNotificationItemEntity> > entitiesToQueue;
                if (string.Equals(this.configuration?[ConfigConstants.NotificationProviderType], NotificationProviderType.Graph.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    entitiesToQueue = BusinessUtilities.SplitList <EmailNotificationItemEntity>(notificationItemEntities.ToList(), this.mSGraphSetting.BatchRequestLimit).ToList();
                }
                else
                {
                    entitiesToQueue = new List <List <EmailNotificationItemEntity> > {
                        notificationItemEntities.ToList()
                    };
                }

                // Queue a single cloud message for all entities created to enable parallel processing.
                var cloudQueue = this.cloudStorageClient.GetCloudQueue(this.notificationQueue);

                foreach (var item in entitiesToQueue)
                {
                    this.logger.TraceVerbose($"Started {nameof(BusinessUtilities.GetCloudMessagesForEntities)} method of {nameof(EmailHandlerManager)}.", traceProps);
                    IList <string> cloudMessages = BusinessUtilities.GetCloudMessagesForEntities(applicationName, item);
                    this.logger.TraceVerbose($"Completed {nameof(BusinessUtilities.GetCloudMessagesForEntities)} method of {nameof(EmailHandlerManager)}.", traceProps);

                    this.logger.TraceVerbose($"Started {nameof(this.cloudStorageClient.QueueCloudMessages)} method of {nameof(EmailHandlerManager)}.", traceProps);
                    await this.cloudStorageClient.QueueCloudMessages(cloudQueue, cloudMessages).ConfigureAwait(false);

                    this.logger.TraceVerbose($"Completed {nameof(this.cloudStorageClient.QueueCloudMessages)} method of {nameof(EmailHandlerManager)}.", traceProps);
                }

                var responses = this.emailManager.NotificationEntitiesToResponse(notificationResponses, notificationItemEntities);
                this.logger.TraceInformation($"Completed {nameof(this.QueueEmailNotifications)} method of {nameof(EmailHandlerManager)}.", traceProps);
                result = true;
                return(responses);
            }
            catch (Exception e)
            {
                this.logger.WriteException(e, traceProps);
                result = false;
                throw;
            }
            finally
            {
                stopwatch.Stop();
                traceProps[AIConstants.Result] = result.ToString(CultureInfo.InvariantCulture);
                var metrics = new Dictionary <string, double>();
                metrics[AIConstants.Duration] = stopwatch.ElapsedMilliseconds;
                this.logger.WriteCustomEvent("QueueEmailNotifications Completed", traceProps, metrics);
            }
        }
        /// <summary>
        /// Processes the notification items as a single batch to Graph.
        /// </summary>
        /// <param name="applicationName">The application Name.</param>
        /// <param name="notificationEntities">List of notification entities to process.</param>
        /// <param name="selectedAccount">selectedAccount.</param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        private async Task ProcessEntitiesInBatch(string applicationName, IList <EmailNotificationItemEntity> notificationEntities, Tuple <AuthenticationHeaderValue, AccountCredential> selectedAccount)
        {
            var traceProps = new Dictionary <string, string>();

            traceProps[AIConstants.Application]            = applicationName;
            traceProps["EmailAccountUsed"]                 = selectedAccount.Item2.AccountName.Base64Encode();
            traceProps[AIConstants.EmailNotificationCount] = notificationEntities.Count.ToString(CultureInfo.InvariantCulture);

            this.logger.TraceInformation($"Started {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.", traceProps);
            if (notificationEntities is null || notificationEntities.Count == 0)
            {
                throw new ArgumentNullException(nameof(notificationEntities));
            }

            var sendForReal = this.mailSettings.Find(a => a.ApplicationName == applicationName).SendForReal;
            var toOverride  = this.mailSettings.Find(a => a.ApplicationName == applicationName).ToOverride;
            var saveToSent  = this.mailSettings.Find(a => a.ApplicationName == applicationName).SaveToSent;

            // Step 1: Prepare graph requests from input entities that shall be sent in a batch to Graph.
            List <GraphBatchRequest>             batchRequests      = new List <GraphBatchRequest>();
            List <GraphRequest>                  graphRequests      = new List <GraphRequest>();
            List <NotificationBatchItemResponse> batchItemResponses = new List <NotificationBatchItemResponse>();
            var nieItems = notificationEntities.ToList();

            foreach (var nie in nieItems)
            {
                EmailNotificationItemEntity item = nie;
                try
                {
                    MessageBody body = await this.emailManager.GetNotificationMessageBodyAsync(applicationName, item).ConfigureAwait(false);

                    EmailMessage message = nie.ToGraphEmailMessage(body);

                    if (!sendForReal)
                    {
                        this.logger.TraceInformation($"Overriding the ToRecipients in {nameof(this.ProcessEntitiesInBatch)} method of {nameof(EmailManager)}.", traceProps);
                        message.ToRecipients = toOverride.Split(Common.ApplicationConstants.SplitCharacter, System.StringSplitOptions.RemoveEmptyEntries)
                                               .Select(torecipient => new Recipient {
                            EmailAddress = new EmailAddress {
                                Address = torecipient
                            }
                        }).ToList();
                        message.CCRecipients      = null;
                        message.BCCRecipients     = null;
                        message.ReplyToRecipients = null;
                    }

                    graphRequests.Add(new GraphRequest()
                    {
                        Id   = nie.NotificationId,
                        Url  = this.mSGraphSetting.SendMailUrl.StartsWith("/", StringComparison.OrdinalIgnoreCase) ? this.mSGraphSetting.SendMailUrl : $"/{this.mSGraphSetting.SendMailUrl}",
                        Body = new EmailMessagePayload(message)
                        {
                            SaveToSentItems = saveToSent
                        },
                        Headers = new GraphRequestHeaders()
                        {
                            ContentType = ApplicationConstants.JsonMIMEType
                        },
                        Method = ApplicationConstants.POSTHttpVerb,
                    });
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    this.logger.TraceInformation($"Caught exception while creating the graph Message {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.", traceProps);
                    batchItemResponses.Add(new NotificationBatchItemResponse {
                        Error = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message, NotificationId = item.NotificationId, Status = HttpStatusCode.PreconditionFailed
                    });
                }
            }

            // Step 2: Split the full list of requests into smaller chunks as per the Graph Batch request limit.
            List <List <GraphRequest> > splitGraphRequests = BusinessUtilities.SplitList(graphRequests, this.mSGraphSetting.BatchRequestLimit).ToList();
            foreach (var graphRequestChunk in splitGraphRequests)
            {
                batchRequests.Add(new GraphBatchRequest()
                {
                    Requests = graphRequestChunk
                });
            }

            // Step 3: Invoke the Graph API for each batch request chunk prepared above.
            foreach (var batchRequest in batchRequests)
            {
                batchItemResponses.AddRange(await this.msGraphProvider.ProcessEmailRequestBatch(selectedAccount.Item1, batchRequest).ConfigureAwait(false));
            }

            bool isAccountIndexIncremented = false;

            // Step 4: Loop through the responses and set the status of the input entities.
            foreach (var item in notificationEntities)
            {
                item.EmailAccountUsed = selectedAccount.Item2.AccountName;
                item.TryCount++;
                item.ErrorMessage = string.Empty; // Reset the error message on next retry.
                var itemResponse = batchItemResponses.Find(resp => resp.NotificationId == item.NotificationId);
                if (itemResponse?.Status == HttpStatusCode.Accepted)
                {
                    item.Status = NotificationItemStatus.Sent;
                }
                else if (item.TryCount <= this.maxTryCount && (itemResponse?.Status == HttpStatusCode.TooManyRequests || itemResponse?.Status == HttpStatusCode.RequestTimeout))
                {
                    // Mark these items as queued and Queue them
                    item.Status               = NotificationItemStatus.Retrying;
                    item.ErrorMessage         = itemResponse?.Error;
                    isAccountIndexIncremented = this.IsMailboxLimitExchausted(itemResponse?.Error, item.NotificationId, item.EmailAccountUsed, isAccountIndexIncremented, traceProps);
                }
                else
                {
                    this.logger.WriteCustomEvent($"{AIConstants.CustomEventMailSendFailed} for notificationId:  {item.NotificationId} ");
                    item.Status       = NotificationItemStatus.Failed;
                    item.ErrorMessage = itemResponse?.Error;
                }
            }

            this.logger.TraceInformation($"Finished {nameof(this.ProcessEntitiesInBatch)} method of {nameof(MSGraphNotificationProvider)}.");
        }