using System; using System.Collections.Generic; using System.Text; using Finsel.AzureCommands; using System.Collections; using System.IO; using Microsoft.Win32; using System.Xml; namespace SagaProcessor { class ATSSagaProcessor { private string sagaPoint = "registrationsaga"; private Authentication pAuth = new Authentication(); /// /// Object that stores information needed to access an instance of /// Azure Table Storage /// public Authentication auth { get { return pAuth; } set { pAuth = value; ad.auth = pAuth; } } AzureQueueStorage aqs = new AzureQueueStorage(); AzureBlobStorage abs = new AzureBlobStorage(); AzureTableStorage ats = new AzureTableStorage(); azureDirect ad = new azureDirect(); azureResults ar = new azureResults(); static int acceptOrDecline = 0; public ATSSagaProcessor(string account, string endPoint, string sharedKey, string keyType) { pAuth = new Authentication(account, "", sharedKey); ad.auth = pAuth; ats.auth = pAuth; aqs.auth = pAuth; abs.auth = pAuth; } #region Notification /// /// Get messages from the Class as it processes /// /// Message data public delegate void LogHandler(string message); private LogHandler mvLogHandler; public void OnLogHandler(LogHandler msgString) { if (msgString != null) { mvLogHandler = msgString; Console.WriteLine(msgString); } } /// /// Notify the calling object of an event /// /// Message of what has happened void NotifyCaller(string msg) { if (mvLogHandler != null) mvLogHandler(msg); else Console.WriteLine(msg); } #endregion public void GetRequests() { // Anything in the Queue we need to get azureResults ar = aqs.Messages(cmdType.get, sagaPoint, "", "", ""); string messageID = string.Empty; string popReceipt = string.Empty; string messageBody = string.Empty; if (ar.Body != null) // We have a message { System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument(); xdoc.LoadXml(ar.Body); System.Xml.XmlNodeList nodes = xdoc.SelectNodes("//QueueMessage"); if (nodes.Count == 0) NotifyCaller( "No message to process"); else foreach (System.Xml.XmlNode node in nodes) { messageID = node.SelectSingleNode("MessageId").InnerText; if (node.SelectNodes("//PopReceipt").Count > 0) popReceipt = node.SelectSingleNode("PopReceipt").InnerText; if (node.SelectNodes("//MessageText").Count > 0) messageBody = node.SelectSingleNode("MessageText").InnerText; NotifyCaller(string.Format("Processing Message ID:{0}",messageID)); ProcessMessage(messageID, popReceipt, messageBody); } } else NotifyCaller("No message to process"); } private void UpdateSagaDetails(string transactionID, int stepNumber, string results, string nextStep) { string sagaUpdateBody = string.Format(sagaUpdateTemplate, transactionID, "Status", stepNumber + 1, nextStep, string.Format("Step{0}", stepNumber.ToString("D15")), results); azureResults ar = ats.Entities(cmdType.merge, sagaPoint, transactionID, "Status", sagaUpdateBody, "", "*"); NotifyCaller(string.Format("TransactionID: {0} Results:{1}",transactionID, results)); } private void UpdateSagaError(string transactionID, string results, string nextStep) { string sagaUpdateBody = string.Format(sagaErrorTemplate , transactionID, "Status", -99, nextStep, "", results); azureResults ar = ats.Entities(cmdType.merge, sagaPoint, transactionID, "Status", sagaUpdateBody, "", "*"); NotifyCaller(string.Format("TransactionID: {0} Results:{1}", transactionID, results)); } private void ProcessMessage(string messageID, string popReceipt, string messageBody) { System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument(); xdoc.LoadXml(messageBody); // Get the ProcessType out of the block string processType = xdoc.SelectSingleNode("//ProcessType[1]").InnerText; int stepNumber = Convert.ToInt16(xdoc.SelectSingleNode("//StepNumber[1]").InnerText); string stepName = xdoc.SelectSingleNode("//StepName[1]").InnerText; string transactionID = xdoc.SelectSingleNode("//TransactionID[1]").InnerText; switch (stepName) { case "PaymentProcessing": // Make call to PaymentProcessing Object string paymentType = xdoc.SelectSingleNode("//PaymentType[1]").InnerText; switch (paymentType) { case "PO": // Get all details and email to accounting to handle UpdateSagaDetails(transactionID, stepNumber, "Forwarded PO to accounting for processing", "AccountingPOProcess"); // No queue message, that will be handled when Accounting process the PO break; case "CreditCard": // Get all details and attempt to authorize if ((acceptOrDecline % 2) == 0) // Every other request is authorized { string registeredUser = xdoc.SelectSingleNode("//UserID[1]").InnerText; UpdateSagaDetails(transactionID, stepNumber, string.Format("Credit card authorization: {0}", Guid.NewGuid().ToString()), "RegistrationComplete"); UpdateRegistrationDetails(transactionID, "Completed"); StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0}", transactionID); sb.Append("RegistrationRegistrationComplete"); sb.AppendFormat("{0}{1}", stepNumber + 1, registeredUser); sb.Append(""); azureResults ar = aqs.Messages(cmdType.post,sagaPoint,sb.ToString(),"",""); } else UpdateSagaError(transactionID, "Credit card declined", "ManualIntervention"); acceptOrDecline++; break; } break; case "RegistrationComplete": string emailUser = xdoc.SelectSingleNode("//UserID[1]").InnerText; azureResults ar1 = ats.Entities(cmdType.get, "vslivelasvegas", "RegisteredUsers", emailUser, "", ""); UpdateSagaDetails(transactionID, 00, string.Format("Emailed {0} with completed registration information",emailUser ), "Completed successfully"); break; default: UpdateSagaDetails(transactionID, -99, string.Format("{0} is an unknown processType", processType), "ManualIntervention"); break; } azureResults ar2 = aqs.Messages(cmdType.delete, sagaPoint, "", string.Format("popreceipt={0}", popReceipt), messageID); } private void UpdateRegistrationDetails(string transactionID, string results) { string registrationDetailsTemplate = @" RegistrationDetails {0} {1} "; azureResults ar1 = ats.Entities(cmdType.merge, "vslivelasvegas", "RegistrationDetails", transactionID, string.Format(registrationDetailsTemplate, transactionID, results), ""); } string sagaUpdateTemplate = @" {0} {1} {2} {3} {5} "; string sagaErrorTemplate = @" {0} {1} {2} {3} {5} "; } }