I've already looked here and found some great advice on managing transactions.
My problem is that I'm also calling a web service in at least one case, logging to a database table. Here's some psuedo-code that might help make things more clear:
customer = batchRefundToProcess.RefundCustomer;
//Validate everything
if (ValidateRefund(batchRefundToProcess) == false)
{
refund.RefundStatusId = (int)REFUNDSTATUSES.RefundDenied;
refund.ReviewedBy = displayUserName;
refund.Update();
return false;
}
//get this customer's payments
List<RefundTran> trans = customer.ARTransactions;
refund.RefundStatusId = (int)REFUNDSTATUSES.RefundInProcess;
refund.ReviewDate = DateTime.Now;
refund.ReviewedBy = displayUserName;
refund.Update();
List<RefundTran> paperTransactions = new List<RefundTran>();
foreach (RefundTran transaction in trans)
{
if (customer.Balance < 0) //balance is negative if we owe them money
{
//processtransaction has the following side effects:
//1. refund detail is created for the tran
//2. customer is billed for the refunded amount, web service is called
var paperTransaction = processTransaction(customer, transaction, refund);
if (paperTransaction != null) //this transaction qualifies for a paper check for one reason or another
{
paperTransactions.Add(paperTransaction);
}
}
}
//get total amount
//basically, the sum total of all their paper check transactions plus whatever's left on their balance, if anything
decimal paperCheckAmount = paperTransactions.Sum(pt => pt.Amount) - customer.Balance;
if (paperTransactions.Count > 0)
{
//cut a check for all the transactions together
AddLineToFile(customer, paperCheckAmount, paperTransactions.First(), REFUNDFILETYPE.ElectronicCheck, refund.RefundId);
}
refund.RefundStatusId = (int)REFUNDSTATUSES.RefundApproved;
refund.ReviewedBy = displayUserName;
refund.Update();
} //end using block
return true;
There are webservice calls in there, and some database logging. I know there's no magic way to "undo" a webservice call to an outside vendor, but how do I keep the database logging from rolling back along with the transaction if it fails? What should I do in the event that I've already made the webservice call? Am I making this too hard? I don't want to bill a customer and then fail on cutting them a check, or worse (in my organization's opinion), cut them a check but fail on billing their account!