Expanding SqlConnection to be more like DBConnection

Also shifting the Connect operation to be async
This commit is contained in:
Benjamin Russell
2016-07-27 18:03:55 -07:00
parent 2ea5cf3457
commit bc0383b6e6
6 changed files with 186 additions and 46 deletions

View File

@@ -6,12 +6,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.SqlTools.EditorServices.Utility; using Microsoft.SqlTools.EditorServices.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Connection namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices
{ {
/// <summary> /// <summary>
/// Main class for the Connection Management services /// Main class for the Connection Management services
@@ -119,25 +121,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// Open a connection with the specified connection details /// Open a connection with the specified connection details
/// </summary> /// </summary>
/// <param name="connectionDetails"></param> /// <param name="connectionDetails"></param>
public ConnectionResult Connect(ConnectionDetails connectionDetails) public async Task<ConnectionResult> Connect(ConnectionDetails connectionDetails)
{ {
// build the connection string from the input parameters // build the connection string from the input parameters
string connectionString = BuildConnectionString(connectionDetails); string connectionString = BuildConnectionString(connectionDetails);
// create a sql connection instance // create a sql connection instance
ISqlConnection connection = this.ConnectionFactory.CreateSqlConnection(); ISqlConnection connection = ConnectionFactory.CreateSqlConnection(connectionString);
// open the database // open the database
connection.OpenDatabaseConnection(connectionString); await connection.OpenAsync();
// map the connection id to the connection object for future lookups // map the connection id to the connection object for future lookups
this.ActiveConnections.Add(++maxConnectionId, connection); ActiveConnections.Add(++maxConnectionId, connection);
// invoke callback notifications // invoke callback notifications
foreach (var activity in this.onConnectionActivities) var onConnectionCallbackTasks = onConnectionActivities.Select(t => t(connection));
{ await Task.WhenAll(onConnectionCallbackTasks);
activity(connection); // TODO: Evaulate if we want to avoid waiting here. We'll need error handling on the other side if we don't wait
}
// return the connection result // return the connection result
return new ConnectionResult() return new ConnectionResult()
@@ -178,7 +179,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
Logger.Write(LogLevel.Verbose, "HandleConnectRequest"); Logger.Write(LogLevel.Verbose, "HandleConnectRequest");
// open connection base on request details // open connection base on request details
ConnectionResult result = ConnectionService.Instance.Connect(connectionDetails); ConnectionResult result = await Connect(connectionDetails);
await requestContext.SendResult(result); await requestContext.SendResult(result);
} }

View File

@@ -3,21 +3,33 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System.Collections.Generic; using System.Data;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts
{ {
/// <summary> /// <summary>
/// Interface for the SQL Connection wrapper /// Interface for the SQL Connection wrapper
/// </summary> /// </summary>
public interface ISqlConnection public interface ISqlConnection : IDbConnection
{ {
/// <summary> ///// <summary>
/// Open a connection to the provided connection string ///// Open a connection to the provided connection string
/// </summary> ///// </summary>
/// <param name="connectionString"></param> ///// <param name="connectionString"></param>
void OpenDatabaseConnection(string connectionString); //void OpenDatabaseConnection(string connectionString);
IEnumerable<string> GetServerObjects(); //IEnumerable<string> GetServerObjects();
string DataSource { get; }
string ServerVersion { get; }
void ClearPool();
Task OpenAsync();
Task OpenAsync(CancellationToken token);
} }
} }

View File

@@ -13,6 +13,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts
/// <summary> /// <summary>
/// Create a new SQL Connection object /// Create a new SQL Connection object
/// </summary> /// </summary>
ISqlConnection CreateSqlConnection(); ISqlConnection CreateSqlConnection(string connectionString);
} }
} }

View File

@@ -3,9 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System.Collections.Generic; using System;
using System.Data; using System.Data;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts
{ {
@@ -21,36 +23,161 @@ namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts
private SqlConnection connection; private SqlConnection connection;
/// <summary> /// <summary>
/// Opens a SqlConnection using provided connection string /// Creates a new instance of the SqlClientConnection with an underlying connection to the
/// database server provided in <paramref name="connectionString"/>.
/// </summary> /// </summary>
/// <param name="connectionString"></param> /// <param name="connectionString">Connection string for the database to connect to</param>
public void OpenDatabaseConnection(string connectionString) public SqlClientConnection(string connectionString)
{ {
this.connection = new SqlConnection(connectionString); connection = new SqlConnection(connectionString);
this.connection.Open();
} }
/// <summary> ///// <summary>
/// Gets a list of database server schema objects ///// Gets a list of database server schema objects
/// </summary> ///// </summary>
/// <returns></returns> ///// <returns></returns>
public IEnumerable<string> GetServerObjects() //public IEnumerable<string> GetServerObjects()
{ //{
// Select the values from sys.tables to give a super basic // // Select the values from sys.tables to give a super basic
// autocomplete experience. This will be replaced by SMO. // // autocomplete experience. This will be replaced by SMO.
SqlCommand command = connection.CreateCommand(); // SqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT name FROM sys.tables"; // command.CommandText = "SELECT name FROM sys.tables";
command.CommandTimeout = 15; // command.CommandTimeout = 15;
command.CommandType = CommandType.Text; // command.CommandType = CommandType.Text;
var reader = command.ExecuteReader(); // var reader = command.ExecuteReader();
List<string> results = new List<string>(); // List<string> results = new List<string>();
while (reader.Read()) // while (reader.Read())
// {
// results.Add(reader[0].ToString());
// }
// return results;
//}
#region ISqlConnection Implementation
#region Properties
public string ConnectionString
{
get { return connection.ConnectionString; }
set { connection.ConnectionString = value; }
}
public int ConnectionTimeout
{
get { return connection.ConnectionTimeout; }
}
public string Database
{
get { return connection.Database; }
}
public string DataSource
{
get { return connection.DataSource; }
}
public string ServerVersion
{
get { return connection.ServerVersion; }
}
public ConnectionState State
{
get { return connection.State; }
}
#endregion
#region Public Methods
public IDbTransaction BeginTransaction()
{
return connection.BeginTransaction();
}
public IDbTransaction BeginTransaction(IsolationLevel il)
{
return connection.BeginTransaction(il);
}
public void ChangeDatabase(string databaseName)
{
connection.ChangeDatabase(databaseName);
}
public void ClearPool()
{
if (connection != null)
{ {
results.Add(reader[0].ToString()); SqlConnection.ClearPool(connection);
} }
return results;
} }
public void Close()
{
connection.Close();
}
public IDbCommand CreateCommand()
{
return connection.CreateCommand();
}
public void Open()
{
connection.Open();
}
public Task OpenAsync()
{
return connection.OpenAsync();
}
public Task OpenAsync(CancellationToken token)
{
return connection.OpenAsync(token);
}
#endregion
#endregion
#region IDisposable Implementation
private bool disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
connection.Dispose();
}
disposed = true;
}
}
~SqlClientConnection()
{
Dispose(false);
}
#endregion
} }
} }

View File

@@ -15,9 +15,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ConnectionServices.Contracts
/// <summary> /// <summary>
/// Creates a new SqlClientConnection object /// Creates a new SqlClientConnection object
/// </summary> /// </summary>
public ISqlConnection CreateSqlConnection() public ISqlConnection CreateSqlConnection(string connectionString)
{ {
return new SqlClientConnection(); return new SqlClientConnection(connectionString);
} }
} }
} }

View File

@@ -7,7 +7,7 @@ using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.WorkspaceServices; using Microsoft.SqlTools.ServiceLayer.WorkspaceServices;
using Microsoft.SqlTools.ServiceLayer.LanguageServices; using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.ConnectionServices;
namespace Microsoft.SqlTools.ServiceLayer namespace Microsoft.SqlTools.ServiceLayer
{ {