public async Task PersistHandledMessage(InboxRecord inboxMessage)
        {
            const string sql = @"MERGE INTO [{0}].[{1}InboxRecord] WITH (updlock, rowlock) AS tgt
                        USING
                          (SELECT @ContentId, @CheckMessageOrderType) AS src (ContentId, CheckMessageOrderType)
                          ON tgt.ContentId = src.ContentId and tgt.CheckMessageOrderType = src.CheckMessageOrderType 
                        WHEN MATCHED THEN
                          UPDATE       
                            SET 
                                ContentVersion = @ContentVersion, 
                                ContentId = @ContentId, 
                                ModifiedAtUtc = @ModifiedAtUtc,
                                MessageId = @MessageId 
                        WHEN NOT MATCHED THEN
                          INSERT (ContentId, ContentVersion, CheckMessageOrderType, ModifiedAtUtc, MessageId) 
                          VALUES (@ContentId, @ContentVersion, @CheckMessageOrderType, @ModifiedAtUtc, @MessageId);";

            object[] parameters = { dbSchemaName, dbTablePrefix };
            await this.Database.ExecuteSqlCommandAsync(
                string.Format(sql, parameters),
                new SqlParameter("@ContentId", inboxMessage.ContentId),
                new SqlParameter("@ContentVersion", inboxMessage.ContentVersion),
                new SqlParameter("@CheckMessageOrderType", inboxMessage.CheckMessageOrderType),
                new SqlParameter("@ModifiedAtUtc", inboxMessage.ModifiedAtUtc),
                new SqlParameter("@MessageId", inboxMessage.MessageId))
            .ConfigureAwait(false);
        }
        public async Task PersistDiscardedMessage(InboxRecord inboxMessage, long latestHandledVersion)
        {
            //Add or update
            const string sql = @"INSERT INTO [{0}].[{1}InboxRecordDiscarded] (ContentId, ContentVersion, LatestContentVersion, CheckMessageOrderType, ModifiedAtUtc, MessageId)
		                        VALUES (@ContentId, @ContentVersion, @LatestContentVersion, @CheckMessageOrderType, @ModifiedAtUtc, @MessageId)"        ;

            object[] parameters = { dbSchemaName, dbTablePrefix };
            await this.Database.ExecuteSqlCommandAsync(
                string.Format(sql, parameters),
                new SqlParameter("@ContentId", inboxMessage.ContentId),
                new SqlParameter("@ContentVersion", inboxMessage.ContentVersion),
                new SqlParameter("@LatestContentVersion", latestHandledVersion),
                new SqlParameter("@CheckMessageOrderType", inboxMessage.CheckMessageOrderType),
                new SqlParameter("@ModifiedAtUtc", inboxMessage.ModifiedAtUtc),
                new SqlParameter("@MessageId", inboxMessage.MessageId))
            .ConfigureAwait(false);
        }
        public override async Task Invoke(IInvokeHandlerContext context, Func <Task> next)
        {
            var session = context.SynchronizedStorageSession;
            var sqlPersistenceSession = session.SqlPersistenceSession();
            var dbContext             = (InboxDbContext)Activator.CreateInstance(typeof(InboxDbContext), sqlPersistenceSession.Connection);

            using (dbContext)
            {
                dbContext.Database.UseTransaction(sqlPersistenceSession.Transaction);

                context.MessageHeaders.TryGetValue("ContentId", out string contentId);
                long contentVersion = GetContentVersionFrom(context.MessageHeaders);

                var checkMessageOrderType = GetCheckMessageOrderType(context);

                var latestHandledVersion = await dbContext.GetLatestMessageVersion(contentId, checkMessageOrderType).ConfigureAwait(false);

                var shouldBeHandled = latestHandledVersion == null || contentVersion > latestHandledVersion;

                var inboxMessage = new InboxRecord
                {
                    ContentId             = contentId,
                    ContentVersion        = contentVersion,
                    CheckMessageOrderType = checkMessageOrderType,
                    MessageId             = Guid.Parse(context.MessageId),
                    ModifiedAtUtc         = DateTime.UtcNow
                };

                if (shouldBeHandled)
                {
                    log.Info($"Handling message: Type: {checkMessageOrderType}, ContentId: {contentId}, ContentVersion: {contentVersion}");
                    await dbContext.PersistHandledMessage(inboxMessage).ConfigureAwait(false);
                    await next().ConfigureAwait(false);
                }
                else
                {
                    string discardedReason = $"Discarding message since a newer version has already been processed: Type: {checkMessageOrderType}, ContentId: {contentId}, ContentVersion: {contentVersion}";
                    log.Info(discardedReason);
                    await dbContext.PersistDiscardedMessage(inboxMessage, latestHandledVersion.GetValueOrDefault()).ConfigureAwait(false);

                    context.Headers.Add("InboxDiscardedReason", discardedReason);
                }
            }
        }