#region License Information /* HeuristicLab * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using HeuristicLab.Services.Hive.Interfaces; using System.Configuration; using System.Data.Common; using System.ServiceModel; using System.Transactions; namespace HeuristicLab.Services.Hive { public class ConnectionProvider : IConnectionProvider { public System.Data.Common.DbConnection GetOpenConnection(string connectionStringName) { ConnectionStringSettings connSettings = ConfigurationManager.ConnectionStrings[connectionStringName]; DbProviderFactory dbProvFact = DbProviderFactories.GetFactory(connSettings.ProviderName); return ConnectionUtilsStorage.Current.GetOpenConnection(dbProvFact, connSettings.ConnectionString); } public void ReleaseConnection(DbConnection connection) { ConnectionUtilsStorage.Current.ReleaseConnection(connection); } } /// /// Based on the connection management developed by jheinzelreiter, /// this class stores transactions + connections, closing connections /// after a transaction has been closed. /// A non-transacted connection might be closed by the user by calling /// ReleaseConnection(connection). /// class ConnectionUtilsStorage : IExtension { private readonly IDictionary> transactedConnections = new Dictionary>(); /// /// Returns an opened DbConnection. If a transaction is present, for /// each unique connection string the same connection is returned. /// /// DbProviderFactory, which should be used to create /// connection /// connection string of the connection /// A instance public DbConnection GetOpenConnection(DbProviderFactory providerFactory, string connectionString) { DbConnection connection = null; Transaction currentTransaction = Transaction.Current; if (currentTransaction == null) { // no transaction context -> return "ordinary" connection connection = CreateOpenConnection(providerFactory, connectionString); } else { // transaction present IDictionary connections = null; lock (transactedConnections) { // check if current transaction already has at least one connection assigned if (!transactedConnections.TryGetValue(currentTransaction, out connections)) { connections = new Dictionary(); transactedConnections[currentTransaction] = connections; } if (!connections.TryGetValue(connectionString, out connection)) { // no connection for this connection string in the current transaction connection = CreateOpenConnection(providerFactory, connectionString); connections[connectionString] = connection; currentTransaction.TransactionCompleted += new TransactionCompletedEventHandler(OnTransactionCompleted); } } } return connection; } /// /// Creates a new, opened DbConnection /// /// connection string of the connection /// DbProviderFactory, which should be used to create /// connection /// A instance private DbConnection CreateOpenConnection(DbProviderFactory providerFactory, string connectionString) { DbConnection connection = providerFactory.CreateConnection(); connection.ConnectionString = connectionString; connection.Open(); return connection; } /// /// Releases a connection. /// (Remark: The connection is closed only when not used in a transaction) /// /// connection to release public void ReleaseConnection(DbConnection connection) { if (connection == null) return; Transaction currentTransaction = Transaction.Current; // close connection if no transaction is active if (currentTransaction == null) connection.Close(); } /// /// Determines, if custom connection handling code should close a connection. /// (Remark: Used for DataReader.CommandBehavior) /// /// public bool ShouldCloseConnection() { return Transaction.Current == null; } /// /// Eventhandler for TransactionScope.TransactionCompleted. /// Closes connections and removes transaction from observed connections. /// /// sender /// TransactionEventArgs private void OnTransactionCompleted(object sender, TransactionEventArgs e) { lock (transactedConnections) { IDictionary connections = null; if (transactedConnections.TryGetValue(e.Transaction, out connections)) { foreach (DbConnection conn in connections.Values) conn.Close(); transactedConnections.Remove(e.Transaction); } } } private static object monitor = new object(); private static ConnectionUtilsStorage _context = new ConnectionUtilsStorage(); public static ConnectionUtilsStorage Current { get { ConnectionUtilsStorage context; if (OperationContext.Current != null) { context = OperationContext.Current.Extensions.Find(); if (context == null) { lock (monitor) { context = OperationContext.Current.Extensions.Find(); if (context == null) { context = new ConnectionUtilsStorage(); OperationContext.Current.Extensions.Add(context); } } } } else { context = _context; } return context; } } public void Attach(OperationContext owner) { } public void Detach(OperationContext owner) { } } }