/// <summary> /// Logs user in/authenticates against StockTrader database. /// </summary> /// <param name="userid">User id to authenticate.</param> /// <param name="password">Password for authentication</param> public AccountDataModel login(string userid, string password) { //Create instance of a DAL, which could be designed for any type of DB backend. dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); //As feature of the StockTrader DAL, you will see dal.Open, dal.BeginTransaction, dal.CommitTransaction, //dal.AbortTransaction and dal.Close methods being invoked in the BSL. The pattern within this BSL is: //a) Create an instance of the DAL; //b) Open the DAL; //c) Start a transaction only if necessary (more than one update/insert/delete involved); //d) You get to pick ADO.NET transaction or System.Transactions or ServicedComponent, it will work with // all of the above; StockTrader lets you choose ADO.NET txs or System.Transactions via config. //e) Close the DAL. This releases the DAL's internal connection back to the connection pool. //The implementation "hides" the type of database being used from the BSL, so this BSL will work //with any type of database you create a DAL for, with no changes in the BSL whatsoever. //System.Transactions and SQL Server 2005 and above and Oracle databases work together //with a new feature called "lightweight transactions"; which means you do not need to have the //same performance penalty you got with Serviced Components for always invoking the tx as a full //two-phase operation with DTC logging. If operating against a single database to SQL Server or Oracle, //across one or more connections involved in a tx, System.Transactions will not promote to a DTC-coordinated tx; and hence will be much faster. //If there are mulitple databases or multiple resources (for example, MSMQ and a database) //used with a System.Transaction tx, on the other hand, the tx will be automatically promoted to the required distributed tx, two-phase commit //with DTC logging required. Our StockTrader DAL is designed to: // 1. Hide DB implementation from BSL so we maintain clean separation of BSL from DAL. // 2. Let you freely call into the DAL from BSL methods as many times as you want *without* // creating new separate DB connections // 3. As a by-product, it also helps you use ADO.NET transactions without worrying about // passing DB connections/transaction objects between tiers; maintaining cleaner separation // of BSL from DAL. If using ADO.NET txs; you can accomplish DB-implementation isolation also with // the Provider Factories introduced with ADO.NET 2.0/.NET 2.0: see for details: // http://msdn2.microsoft.com/en-us/library/ms379620(VS.80).aspx //Note Open() is not really necessary, since the DAL will open a new connection automatically //if its internal connection is not already open. It's also free to open up more connections, if desired. //We use Open() to stick with a consistent pattern in this application, since the Close() method IS //important. Look for this pattern in all BSL methods below; with a transaction scope defined //only for operations that actually require a transaction per line (c) above. dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING); try { return dalCustomer.login(userid, password, Settings.USE_SALTEDHASH_PASSWORDS); } catch { throw; } finally { //Always close the DAL, this releases its primary DB connection. dalCustomer.Close(); } }
/// <summary> /// Registers/adds new user to database. /// </summary> /// <param name="userID">User id for account creation/login purposes as specified by user.</param> /// <param name="password">Password as specified by user.</param> /// <param name="fullname">Name as specified by user.</param> /// <param name="address">Address as specified by user.</param> /// <param name="email">Email as specified by user.</param> /// <param name="creditcard">Credit card number as specified by user.</param> /// <param name="openBalance">Open balance as specified by user. </param> public AccountDataModel register(string userID, string password, string fullname, string address, string email, string creditcard, decimal openBalance) { //Switch is two let you configure which transaction model you want to benchmark/test. switch (Settings.TRANSACTION_MODEL) { case (StockTraderUtility.TRANSACTION_MODEL_SYSTEMDOTTRANSACTION_TRANSACTION): { //This short try/catch block is introduced to deal with idle-timeout on SQL Azure //connections. It may not be required in the near future, but as of publication //SQL Azure disconnects idle connections after 30 minutes. While command retry-logic //in the DAL automatically deals with this, when performing a tx, with the BSL handling //tx boundaries, we want to go into the tx with known good connections. The try/catch below //ensures this. try { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING); dalCustomer.getSQLContextInfo(); } catch { } finally { dalCustomer.Close(); } System.Transactions.TransactionOptions txOps = new TransactionOptions(); txOps.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; txOps.Timeout = TimeSpan.FromSeconds((double)Settings.SYSTEMDOTTRANSACTION_TIMEOUT); //Start our System.Transactions tx with the options set above. System.Transactions //will handle rollbacks automatically if there is an exception; note the //difference between the System.Transaction case and the ADO.NET transaction case; //and where the dal.Open() happens (which opens a 'hidden' DB connection in DAL). //System.Transactions will automatically enlist ANY connection //opened within the tx scope in the transaction for you. Since it supports distributed //tx's; it frees you quite a bit, with the caveat of the overhead of doing a distributed //tx when you do not need one. Hence: lightweight System.Transactions with an auto-promote to DTC //only if needed, meaning two or more operations use database connections spanning physicall different databases. //ADO.NET txs always require an already-open connection before starting a tx, and txs cannot span multiple databases, just tables. using (TransactionScope tx = new TransactionScope(TransactionScopeOption.Required, txOps)) { //Now open the connection, after entering tx scope. dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { AccountDataModel newCustomer = addNewRegisteredUser(userID, password, fullname, address, email, creditcard, openBalance); //Scope complete, commit work. tx.Complete(); return newCustomer; } catch { //no rollback needed, infrastructure will never commit without //scope.Complete() and immediately issue rollback on and unhandled //exception. throw; } finally { dalCustomer.Close(); } } } case (StockTraderUtility.TRANSACTION_MODEL_ADONET_TRANSACTION): { //ADO.NET TX case: First you need to open the connecton. dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; //Now you start TX dalCustomer.BeginADOTransaction(); try { AccountDataModel newCustomer = addNewRegisteredUser(userID, password, fullname, address, email, creditcard, openBalance); //done, commit. dalCustomer.CommitADOTransaction(); return newCustomer; } catch { //explicit rollback needed. dalCustomer.RollBackTransaction(); throw; } finally { //ALWAYS call dal.Close is using StockTrader DAL implementation; //this is equivalent to calling Connection.Close() in the DAL -- //but for a generic DB backend as far as the BSL is concerned. dalCustomer.Close(); } } } throw new Exception(Settings.ENABLE_GLOBAL_SYSTEM_DOT_TRANSACTIONS_CONFIGSTRING + ": " + StockTraderUtility.EXCEPTION_MESSAGE_INVALID_TXMMODEL_CONFIG + " Repository ConfigKey table."); }
/// <summary> /// Updates account profile data for a user. /// </summary> /// <param name="profileData">Profile data model class with updated info.</param> public AccountProfileDataModel updateAccountProfile(AccountProfileDataModel profileData) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { return dalCustomer.update(profileData, Settings.USE_SALTEDHASH_PASSWORDS); } catch { throw; } finally { dalCustomer.Close(); } }
/// <summary> /// Gets a holding for a user. Transforms data from DataContract to model UI class for HTML display. /// </summary> /// <param name="userID">User id to retrieve data for.</param> /// <param name="holdingID">Holding id to retrieve data for.</param> public HoldingDataModel getHolding(string userID, int holdingID) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { return dalCustomer.getHolding(userID, holdingID); } catch { throw; } finally { dalCustomer.Close(); } }
/// <summary> /// Gets any closed orders for a user--orders that have been processed. Also updates status to complete. /// </summary> /// <param name="userID">User id to retrieve data for.</param> public List<OrderDataModel> getClosedOrders(string userID) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { return dalCustomer.getClosedOrders(userID); } catch { throw; } finally { dalCustomer.Close(); } }
/// <summary> /// Gets specific top n orders for a user. Transforms data from DataContract to model UI class for HTML display. /// </summary> /// <param name="userID">User id to retrieve data for.</param> public List<OrderDataModel> getTopOrders(string userID) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { return dalCustomer.getOrders(userID, true, Settings.MAX_QUERY_TOP_ORDERS,Settings.MAX_QUERY_ORDERS); } catch { throw; } finally { dalCustomer.Close(); } }
/// <summary> /// Gets account profile data for a user. Transforms data from DataContract to model UI class for HTML display. /// </summary> /// <param name="userID">User id to retrieve data for.</param> public AccountProfileDataModel getAccountProfileData(string userID) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { return dalCustomer.getAccountProfileData(userID); } catch { throw; } finally { dalCustomer.Close(); } }
/// <summary> /// Logs a user out--updates logout count. /// </summary> /// <param name="userID">User id to logout.</param> public void logout(string userID) { dalCustomer = Trade.DALFactory.Customer.Create(Settings.DAL); dalCustomer.Open(Settings.TRADEDB_SQL_CONN_STRING);; try { dalCustomer.logOutUser(userID); return; } catch { throw; } finally { dalCustomer.Close(); } }