//TODO: Figure out how to handle Key / Certificate events... do we just ignore those?
        public FormattedProcessRequest FormatRequest()
        {
            JObject item;

            try
            {
                item = JObject.Parse(OriginalMessageJson);
            }
            catch (Newtonsoft.Json.JsonReaderException ex)
            {
                string json = Encoding.UTF8.GetString(Convert.FromBase64String(OriginalMessageJson));
                item = JObject.Parse(json);
                OriginalMessageJson = json;
            }

            FormattedProcessRequest.RequestedAction action = FormattedProcessRequest.RequestedAction.DoNothing;
            FormattedProcessRequest.SecretEvent     et     = FormattedProcessRequest.SecretEvent.Unknown;

            string eventType = item.GetValue("eventType").ToString();

            if (!string.IsNullOrWhiteSpace(eventType))
            {
                switch (eventType)
                {
                case KnownEvents.Secret.Created:
                    et     = FormattedProcessRequest.SecretEvent.Created;
                    action = FormattedProcessRequest.RequestedAction.ScheduleDependencyUpdates;
                    break;

                case KnownEvents.Secret.Expiring:
                    et     = FormattedProcessRequest.SecretEvent.Expiring;
                    action = FormattedProcessRequest.RequestedAction.Rotate;
                    break;

                case KnownEvents.Secret.Expired:
                    et     = FormattedProcessRequest.SecretEvent.Expired;
                    action = FormattedProcessRequest.RequestedAction.Cleanup;
                    break;
                }
            }

            FormattedProcessRequest request = new FormattedProcessRequest(OriginalMessageJson, action)
            {
                Event               = et,
                ObjectType          = FormattedProcessRequest.SecretType.Unknown,
                ParentTransactionId = TransactionId
            };

            string topic = item.GetValue("topic").ToString();

            if (!string.IsNullOrWhiteSpace(topic))
            {
                string startToken = "/subscriptions/", endToken = "/resourceGroups/";

                int startIndex = topic.IndexOf(startToken);
                if (startIndex >= 0)
                {
                    startIndex += startToken.Length;
                    int endIndex = topic.IndexOf(endToken, startIndex);
                    if (endIndex > startIndex)
                    {
                        request.SubscriptionId = topic.Substring(startIndex, endIndex - startIndex);
                    }
                }
            }

            JObject data = item.GetValue("data") as JObject;

            if (null != data)
            {
                request.ObjectUri  = data.GetValue("Id").ToString();
                request.ObjectName = data.GetValue("ObjectName").ToString();
                request.VaultName  = data.GetValue("VaultName").ToString();

                string ot = data.GetValue("ObjectType").ToString();
                if (false == string.IsNullOrWhiteSpace(ot))
                {
                    switch (ot.ToLower())
                    {
                    case "secret":
                        request.ObjectType = FormattedProcessRequest.SecretType.Secret;
                        break;

                    case "certificate":
                        request.ObjectType = FormattedProcessRequest.SecretType.Certificate;
                        break;

                    case "key":
                        request.ObjectType = FormattedProcessRequest.SecretType.Key;
                        break;
                    }
                }
                return(request);
            }

            return(null);
        }
        protected override async Task OnRecordTransactionStartAsync(Common.Tracking.TrackingContext context)
        {
            Ef.Entities.Transaction tx = await _dbContext.Transactions.FirstOrDefaultAsync(t => t.TransactionId == context.Request.TransactionId);

            if (null == tx)
            {
                string key = string.Empty, uri = string.Empty;
                FormattedProcessRequest.SecretEvent     evnt = FormattedProcessRequest.SecretEvent.Unknown;
                FormattedProcessRequest.RequestedAction action = FormattedProcessRequest.RequestedAction.Unknown;
                TransactionPurpose purpose = TransactionPurpose.Unknown;

                FormattedProcessRequest fpr = context.Request as FormattedProcessRequest;
                if (null == fpr)
                {
                    fpr = (context.Request as RawProcessRequest)?.FormatRequest();
                }

                if (null != fpr)
                {
                    uri     = fpr.ObjectUri;
                    evnt    = fpr.Event;
                    action  = fpr.Action;
                    purpose = TransactionPurpose.ExecuteRotationProcess;
                }

                if (context.Request is RawProcessRequest)
                {
                    action  = FormattedProcessRequest.RequestedAction.Unknown;
                    purpose = TransactionPurpose.ProcessKVEvent;
                }

                if (!string.IsNullOrWhiteSpace(uri))
                {
                    var s = SecretManagement.Contracts.Data.SecretBase.FromKeyvaultUri(uri);
                    if (null != s)
                    {
                        key = s.Key;
                    }
                }

                tx = new Ef.Entities.Transaction()
                {
                    TransactionId = context.Request.TransactionId,
                    SecretKey     = key,
                    SecretUri     = uri,
                    Action        = action,
                    Event         = evnt,
                    Purpose       = purpose
                };

                if (context.Request.ParentTransactionId != Guid.Empty)
                {
                    tx.ParentTransaction = await _dbContext.Transactions.FirstOrDefaultAsync(t => t.TransactionId == context.Request.ParentTransactionId);
                }

                _dbContext.Transactions.Add(tx);
            }

            Ef.Entities.Attempt attempt = new Ef.Entities.Attempt()
            {
                StartingStatus = context.Result.Status,
                StartTimeUtc   = context.StartTime,
                Transaction    = tx
            };

            List <Ef.Entities.Attempt> attempts = tx.Attempts?.ToList();

            if (null == attempts)
            {
                attempts = new List <Ef.Entities.Attempt>();
            }
            attempts.Add(attempt);
            tx.Attempts = attempts;

            _dbContext.Attempts.Add(attempt);

            await _dbContext.SaveChangesAsync();

            context.TrackingState.Add(this, attempt.AttemptId);
        }