diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs
index 82542721..8388da10 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs
@@ -18,6 +18,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
///
public class ConnectionInfo
{
+ private static readonly DateTime UnixEpochUtc = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+
///
/// Constructor
///
@@ -27,7 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
OwnerUri = ownerUri;
ConnectionDetails = details;
ConnectionId = Guid.NewGuid();
- IntellisenseMetrics = new InteractionMetrics(new int[] {50, 100, 200, 500, 1000, 2000});
+ IntellisenseMetrics = new InteractionMetrics(new int[] { 50, 100, 200, 500, 1000, 2000 });
}
///
@@ -72,11 +74,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// Returns true if the db connection is to a SQL db instance
///
public bool IsSqlDb { get; set; }
-
+
+ ///
/// Returns true if the sql connection is to a DW instance
///
public bool IsSqlDW { get; set; }
+ ///
+ /// Returns true if Authentication mode is AzureMFA, determines if Access token is in use.
+ ///
+ public bool IsAzureAuth { get; set; }
+
///
/// Returns the connection Engine Edition
///
@@ -158,8 +166,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
public void RemoveConnection(string connectionType)
{
Validate.IsNotNullOrEmptyString("Connection Type", connectionType);
- DbConnection connection;
- ConnectionTypeToConnectionMap.TryRemove(connectionType, out connection);
+ ConnectionTypeToConnectionMap.TryRemove(connectionType, out _);
}
///
@@ -169,18 +176,44 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
{
foreach (var type in AllConnectionTypes)
{
- DbConnection connection;
- ConnectionTypeToConnectionMap.TryRemove(type, out connection);
+ ConnectionTypeToConnectionMap.TryRemove(type, out _);
}
- }
+ }
///
/// Updates the Auth Token and Expires On fields
///
- public void UpdateAuthToken(string token, int expiresOn)
+ public bool TryUpdateAccessToken(SecurityToken? securityToken)
{
- ConnectionDetails.AzureAccountToken = token;
- ConnectionDetails.ExpiresOn = expiresOn;
+ if (securityToken != null && !string.IsNullOrEmpty(securityToken.Token) && IsAzureAuth && IsAccessTokenExpired)
+ {
+ ConnectionDetails.AzureAccountToken = securityToken.Token;
+ ConnectionDetails.ExpiresOn = securityToken.ExpiresOn;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Returns true if Access token saved in connection details is expired or about to expire in 2 minutes.
+ ///
+ private bool IsAccessTokenExpired
+ {
+ get
+ {
+ if (IsAzureAuth && ConnectionDetails.ExpiresOn != null && double.TryParse(ConnectionDetails.ExpiresOn.ToString(), out var expiresOn))
+ {
+ DateTime dateTime = UnixEpochUtc.AddSeconds(expiresOn);
+
+ // Check if access token is already expired or shall expire in 2 minutes.
+ if (dateTime <= DateTime.UtcNow.AddMinutes(2))
+ {
+ Logger.Verbose("Access token found expired.");
+ return true;
+ }
+ }
+ return false;
+ }
}
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
index 0792e0b8..256f5923 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
@@ -304,7 +304,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
return;
}
this.TokenUpdateUris.Remove(tokenRefreshedParams.Uri, out var result);
- connection.UpdateAuthToken(tokenRefreshedParams.Token, tokenRefreshedParams.ExpiresOn);
+ connection.TryUpdateAccessToken(new SecurityToken() { Token = tokenRefreshedParams.Token, ExpiresOn = tokenRefreshedParams.ExpiresOn });
}
///
@@ -585,6 +585,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
connectionInfo.MajorVersion = serverInfo.ServerMajorVersion;
connectionInfo.IsSqlDb = serverInfo.EngineEditionId == (int)DatabaseEngineEdition.SqlDatabase;
connectionInfo.IsSqlDW = (serverInfo.EngineEditionId == (int)DatabaseEngineEdition.SqlDataWarehouse);
+ // Determines that access token is used for creating connection.
+ connectionInfo.IsAzureAuth = connectionInfo.ConnectionDetails.AuthenticationType == "AzureMFA";
connectionInfo.EngineEdition = (DatabaseEngineEdition)serverInfo.EngineEditionId;
// Azure Data Studio supports SQL Server 2014 and later releases.
response.IsSupportedVersion = serverInfo.IsCloud || serverInfo.ServerMajorVersion >= 12;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/RefreshTokenNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/RefreshTokenNotification.cs
index 9cf02e81..e41498ef 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/RefreshTokenNotification.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/RefreshTokenNotification.cs
@@ -7,7 +7,7 @@ using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
{
- class RefreshTokenParams
+ public class RefreshTokenParams
{
///
/// ID of the tenant
@@ -39,14 +39,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
///
/// Refresh token request mapping entry
///
- class RefreshTokenNotification
+ public class RefreshTokenNotification
{
public static readonly
EventType Type =
EventType.Create("account/refreshToken");
}
- class TokenRefreshedParams
+ public class TokenRefreshedParams
{
///
/// Gets or sets the refresh token.
@@ -64,7 +64,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
public string Uri { get; set; }
}
- class TokenRefreshedNotification
+ public class TokenRefreshedNotification
{
public static readonly
EventType Type =
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityToken.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityToken.cs
new file mode 100644
index 00000000..622a4460
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityToken.cs
@@ -0,0 +1,25 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
+{
+ public class SecurityToken
+ {
+ ///
+ /// Gets or sets the refresh token.
+ ///
+ public string Token { get; set; }
+
+ ///
+ /// Gets or sets the token expiration, a Unix epoch
+ ///
+ public int? ExpiresOn { get; set; }
+
+ ///
+ /// Gets or sets the token type, e.g. 'Bearer'
+ ///
+ public string? TokenType { get; set; }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityTokenRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityTokenRequest.cs
index bbcefd1c..25608c96 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityTokenRequest.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/SecurityTokenRequest.cs
@@ -7,7 +7,7 @@ using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
{
- class RequestSecurityTokenParams
+ class RequestSecurityTokenParams
{
///
/// Gets or sets the address of the authority to issue token.
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs
index 3db9f926..34056387 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs
@@ -4,6 +4,7 @@
//
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
{
@@ -49,6 +50,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
/// Path identifying the node to expand. See for details
///
public string NodePath { get; set; }
+
+ ///
+ /// Security token for AzureMFA authentication for refresing access token on connection.
+ ///
+ public SecurityToken? SecurityToken { get; set; }
}
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs
index 15fb4c20..5601295a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs
@@ -10,7 +10,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
///
/// Parameters to the .
///
- public class RefreshParams: ExpandParams
+ public class RefreshParams : ExpandParams
{
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs
index 54f98e2a..2a91d8b7 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs
@@ -240,14 +240,14 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// Expands this node and returns its children
///
/// Children as an IList. This is the raw children collection, not a copy
- public IList Expand(string name, CancellationToken cancellationToken)
+ public IList Expand(string name, CancellationToken cancellationToken, string? accessToken = null)
{
// TODO consider why solution explorer has separate Children and Items options
if (children.IsInitialized)
{
return children;
}
- PopulateChildren(false, name, cancellationToken);
+ PopulateChildren(false, name, cancellationToken, accessToken);
return children;
}
@@ -255,19 +255,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// Expands this node and returns its children
///
/// Children as an IList. This is the raw children collection, not a copy
- public IList Expand(CancellationToken cancellationToken)
+ public IList Expand(CancellationToken cancellationToken, string? accessToken = null)
{
- return Expand(null, cancellationToken);
+ return Expand(null, cancellationToken, accessToken);
}
///
/// Refresh this node and returns its children
///
/// Children as an IList. This is the raw children collection, not a copy
- public virtual IList Refresh(CancellationToken cancellationToken)
+ public virtual IList Refresh(CancellationToken cancellationToken, string? accessToken = null)
{
// TODO consider why solution explorer has separate Children and Items options
- PopulateChildren(true, null, cancellationToken);
+ PopulateChildren(true, null, cancellationToken, accessToken);
return children;
}
@@ -319,7 +319,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
return Parent as T;
}
- protected virtual void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken)
+ protected virtual void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null)
{
Logger.Write(TraceEventType.Verbose, string.Format(CultureInfo.InvariantCulture, "Populating oe node :{0}", this.GetNodePath()));
Debug.Assert(IsAlwaysLeaf == false);
@@ -335,6 +335,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
children.Clear();
BeginChildrenInit();
+ // Update access token for future queries
+ context.UpdateAccessToken(accessToken);
+
try
{
ErrorMessage = null;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs
index 9a95825f..678df5cc 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs
@@ -212,7 +212,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
}
else
{
- RunExpandTask(session, expandParams);
+ bool refreshNeeded = session.ConnectionInfo.TryUpdateAccessToken(expandParams.SecurityToken);
+ RunExpandTask(session, expandParams, refreshNeeded);
return true;
}
};
@@ -239,6 +240,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
}
else
{
+ session.ConnectionInfo.TryUpdateAccessToken(refreshParams.SecurityToken);
RunExpandTask(session, refreshParams, true);
}
await context.SendResult(true);
@@ -373,12 +375,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
}
- internal Task ExpandNode(ObjectExplorerSession session, string nodePath, bool forceRefresh = false)
+ internal Task ExpandNode(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null)
{
- return Task.Run(() => QueueExpandNodeRequest(session, nodePath, forceRefresh));
+ return Task.Run(() => QueueExpandNodeRequest(session, nodePath, forceRefresh, securityToken));
}
- internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, string nodePath, bool forceRefresh = false)
+ internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null)
{
NodeInfo[] nodes = null;
TreeNode node = session.Root.FindNodeByPath(nodePath);
@@ -432,15 +434,21 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
waitForLockTimeout: timeout,
bindOperation: (bindingContext, cancelToken) =>
{
+ if (!session.ConnectionInfo.IsAzureAuth)
+ {
+ // explicitly set null here to prevent setting access token for non-Azure auth modes.
+ securityToken = null;
+ }
+
if (forceRefresh)
{
Logger.Verbose($"Forcing refresh for {nodePath}");
- nodes = node.Refresh(cancelToken).Select(x => x.ToNodeInfo()).ToArray();
+ nodes = node.Refresh(cancelToken, securityToken?.Token).Select(x => x.ToNodeInfo()).ToArray();
}
else
{
Logger.Verbose($"Expanding {nodePath}");
- nodes = node.Expand(cancelToken).Select(x => x.ToNodeInfo()).ToArray();
+ nodes = node.Expand(cancelToken, securityToken?.Token).Select(x => x.ToNodeInfo()).ToArray();
}
response.Nodes = nodes;
response.ErrorMessage = node.ErrorMessage;
@@ -635,7 +643,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
private async Task ExpandNodeAsync(ObjectExplorerSession session, ExpandParams expandParams, CancellationToken cancellationToken, bool forceRefresh = false)
{
ExpandResponse response = null;
- response = await ExpandNode(session, expandParams.NodePath, forceRefresh);
+ response = await ExpandNode(session, expandParams.NodePath, forceRefresh, expandParams.SecurityToken);
if (cancellationToken.IsCancellationRequested)
{
Logger.Write(TraceEventType.Verbose, "OE expand canceled");
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/DatabaseTreeNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/DatabaseTreeNode.cs
index 3c98ca9e..04b9ca47 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/DatabaseTreeNode.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/DatabaseTreeNode.cs
@@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
internal partial class DatabaseTreeNode
{
- public DatabaseTreeNode(ServerNode serverNode, string databaseName): this()
+ public DatabaseTreeNode(ServerNode serverNode, string databaseName) : this()
{
Parent = serverNode;
NodeValue = databaseName;
@@ -52,12 +52,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
}
}
- protected override void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken)
+ protected override void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null)
{
var smoQueryContext = this.GetContextAs();
if (IsAccessible(smoQueryContext))
{
- base.PopulateChildren(refresh, name, cancellationToken);
+ base.PopulateChildren(refresh, name, cancellationToken, accessToken);
}
else
{
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoExtensions.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoExtensions.cs
new file mode 100644
index 00000000..6bc5bf8b
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoExtensions.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+using Microsoft.SqlServer.Management.Smo;
+using Microsoft.SqlTools.ServiceLayer.Connection;
+
+namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
+{
+ internal static class SmoExtensions
+ {
+ ///
+ /// Updates access token on the connection context of instance.
+ ///
+ /// (this) SMO SQL Object containing connection context.
+ /// Access token
+ public static void UpdateAccessToken(this SqlSmoObject sqlObj, string accessToken)
+ {
+ if (sqlObj != null && !string.IsNullOrEmpty(accessToken)
+ && sqlObj.ExecutionManager != null
+ && sqlObj.ExecutionManager.ConnectionContext != null)
+ {
+ sqlObj.ExecutionManager.ConnectionContext.AccessToken = new AzureAccessToken(accessToken);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs
index 1752588b..059c65b0 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs
@@ -46,17 +46,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
///
/// The server SMO will query against
///
- public Server Server {
+ public Server Server
+ {
get
{
return GetObjectWithOpenedConnection(server);
- }
+ }
}
///
/// Optional Database context object to query against
///
- public Database Database {
+ public Database Database
+ {
get
{
return GetObjectWithOpenedConnection(database);
@@ -70,7 +72,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
///
/// Parent of a give node to use for queries
///
- public SmoObjectBase Parent {
+ public SmoObjectBase Parent
+ {
get
{
return GetObjectWithOpenedConnection(parent);
@@ -86,7 +89,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
/// for specific SMO types
///
public IMultiServiceProvider ServiceProvider { get; private set; }
-
+
///
/// Helper method to cast a parent to a specific type
///
@@ -116,7 +119,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
ObjectExplorerService service = ServiceProvider.GetService();
if (service == null)
{
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
SqlTools.Hosting.SR.ServiceNotFound, nameof(ObjectExplorerService)));
}
@@ -147,7 +150,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
get
{
- if(validFor == 0)
+ if (validFor == 0)
{
validFor = ServerVersionHelper.GetValidForFlag(SqlServerType, Database);
}
@@ -169,6 +172,31 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
return smoObj;
}
+ ///
+ /// Updates access token on parent connection context.
+ ///
+ /// Acquired access token
+ public void UpdateAccessToken(string? accessToken)
+ {
+ if (!string.IsNullOrEmpty(accessToken))
+ {
+ // Update all applicable nodes that could contain access token
+ // to prevent stale token from being re-used.
+ if (server != null)
+ {
+ (server as SqlSmoObject).UpdateAccessToken(accessToken);
+ }
+ if (database != null)
+ {
+ (database as SqlSmoObject).UpdateAccessToken(accessToken);
+ }
+ if (parent != null)
+ {
+ (parent as SqlSmoObject).UpdateAccessToken(accessToken);
+ }
+ }
+ }
+
///
/// Ensures the server objects connection context is open. This is used by all child objects, and
/// the only way to easily access is via the server object. This should be called during access of
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoWrapper.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoWrapper.cs
index 7adf74e3..773a81d7 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoWrapper.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoWrapper.cs
@@ -14,11 +14,21 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
///
internal class SmoWrapper
{
+ ///
+ /// Creates instance of from provided instance.
+ ///
+ /// Server connection instance.
+ /// Server instance.
public virtual Server CreateServer(ServerConnection serverConn)
{
return serverConn == null ? null : new Server(serverConn);
}
+ ///
+ /// Checks if connection is open on the instance.
+ ///
+ /// SMO Object containing connection context.
+ /// True if connection is open, otherwise false.
public virtual bool IsConnectionOpen(SmoObjectBase smoObj)
{
SqlSmoObject sqlObj = smoObj as SqlSmoObject;
@@ -28,6 +38,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
&& sqlObj.ExecutionManager.ConnectionContext.IsOpen;
}
+ ///
+ /// Opens connection on the connection context of instance.
+ ///
+ /// SMO Object containing connection context.
public virtual void OpenConnection(SmoObjectBase smoObj)
{
SqlSmoObject sqlObj = smoObj as SqlSmoObject;
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Utility/LiveConnectionHelper.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Utility/LiveConnectionHelper.cs
index 7d8ce12f..3e960c1d 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Utility/LiveConnectionHelper.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Utility/LiveConnectionHelper.cs
@@ -18,9 +18,10 @@ using System.Threading;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility
{
- public class LiveConnectionException : Exception {
- public LiveConnectionException(string message)
- : base(message) { }
+ public class LiveConnectionException : Exception
+ {
+ public LiveConnectionException(string message)
+ : base(message) { }
}
public class LiveConnectionHelper
@@ -48,7 +49,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility
public static TestConnectionResult InitLiveConnectionInfo(string databaseName = null, string ownerUri = null)
=> InitLiveConnectionInfoAsync(databaseName, ownerUri, ServiceLayer.Connection.ConnectionType.Default).ConfigureAwait(false).GetAwaiter().GetResult();
- public static async Task InitLiveConnectionInfoAsync(string databaseName = "master", string ownerUri = null,
+ public static async Task InitLiveConnectionInfoAsync(string databaseName = "master", string ownerUri = null,
string connectionType = ServiceLayer.Connection.ConnectionType.Default, TestServerType serverType = TestServerType.OnPrem)
{
ScriptFile scriptFile = null;
@@ -58,7 +59,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility
scriptFile = TestServiceProvider.Instance.WorkspaceService.Workspace.GetFile(ownerUri);
ownerUri = scriptFile.ClientUri;
}
- if (string.IsNullOrEmpty(databaseName))
+ if (string.IsNullOrEmpty(databaseName))
{
databaseName = "master";
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/ObjectExplorerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/ObjectExplorerServiceTests.cs
index aa7b6667..4ffdb32b 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/ObjectExplorerServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/ObjectExplorerServiceTests.cs
@@ -295,7 +295,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
public void FindNodeCanExpandParentNodes()
{
var mockTreeNode = new Mock();
- object[] populateChildrenArguments = { ItExpr.Is(x => x == false), ItExpr.IsNull(), new CancellationToken() };
+ object[] populateChildrenArguments = { ItExpr.Is(x => x == false), ItExpr.IsNull(), new CancellationToken(), ItExpr.IsNull() };
mockTreeNode.Protected().Setup("PopulateChildren", populateChildrenArguments);
mockTreeNode.Object.IsAlwaysLeaf = false;