// .Net StockTrader Sample WCF Application for Benchmarking, Performance Analysis and Design Considerations for Service-Oriented Applications //====================================================================================================== // The Order Processor Service implementation class/business logic. //====================================================================================================== using System; using System.Configuration; using System.Diagnostics; using System.Messaging; using System.Transactions; using System.ServiceModel; using System.ServiceModel.Channels; using System.Runtime.Serialization; //using ConfigService.ServiceConfigurationBase; //using ConfigService.ServiceConfigurationUtility; //using ConfigService.ServiceConfigurationHelper; using Trade.BusinessServiceDataContract; using Trade.OrderProcessorContract; using Trade.OrderProcessorServiceConfigurationSettings; using Trade.Utility; //using Trade.OrderProcessorAsyncClient; namespace Trade.OrderProcessorImplementation { /// /// Service class which implements the Order Processor service contract. /// ReleaseServiceInstanceOnTransactionComplete is marked as false to support transacted batches from the /// transacted (persisted) durable MSMQ message queue. This is required! /// [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)] public class OrderProcessor : IOrderProcessor { public OrderProcessor() { } /// /// Interesting in that this service contract is a one-way contract. However, it // turns out this online check works fine in that we are loosely couple when working with MSMQ // and still tightly coupled on one-way TCP or HTTP bindings. The behavior is such // that this method will fail from calling client only on TCP/HTTP one-way (Async) // bindings, which happens regardless on any method call; but will not fail on MSMQ bindings // if the messaging service is running. If MSMQ messaging service is not running at the endpoint, // we will have endpoint not found detection as desired. /// public void isOnline() { return; } /// /// SubmitOrder service operation is a service operation that processes order messages from the client /// coming in via TCP, HTTP, or a non-transacted (volatile) MSMQ WCF binding from either the BSL or another remote instance /// of the Order Processor Service running in 'Forward' mode. /// This method *always* uses a System.Transaction tx to ensure database integrity. /// However, since it is receiving from a non-persisted format, the order could possibly be lost /// even as database integrity is maintained on the processing of the order itself. /// This is because if a received order is not processed successfully to the database, the message /// will not be automatically preserved by the source it is being received from since that source /// is not a durable (persisted) source. /// /// Order to submit. public void SubmitOrder(OrderDataModel order) { System.Transactions.TransactionOptions txOps = new TransactionOptions(); txOps.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; txOps.Timeout = TimeSpan.FromSeconds(Settings.SYSTEMDOTTRANSACTION_TIMEOUT); //Start our System.Transactions tx with the options set above. using (TransactionScope tx = new TransactionScope(TransactionScopeOption.Required, txOps)) { try { processOrder(order); //Complete transaction scope! tx.Complete(); } catch { throw; } } return; } /// /// Processes the order and creates holding, or sells stock. /// /// Order to process. private void processOrder(OrderDataModel queuedOrder) { //You could extend this application by transforming the order message //as it comes in to another format, if required. In this case, //no transformation actually takes place since the types are the same. //You can imagine different systems bridged might have different schema, //however, and transformations could be rather easily accomplished here. if (queuedOrder.orderID % Settings.DISPLAYNUMBERORDERITERATIONS == 0) { string message = string.Format("Processing Order {0}, symbol {1}, type {2}.", queuedOrder.orderID.ToString(), queuedOrder.symbol, queuedOrder.orderType); StockTraderUtility.writeConsoleMessage(message + "\n",EventLogEntryType.Information,false, Settings.EVENT_LOG); } ProcessOrder orderService = new ProcessOrder(); orderService.ProcessAndCompleteOrder(queuedOrder); return; } } }