mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Adding extension service host for extension services (#1808)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.SqlTools.Hosting.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.Kusto.ServiceLayer.Utility
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.SqlTools.Credentials.Utility;
|
||||
using Microsoft.SqlTools.Hosting.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
@@ -40,7 +39,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
|
||||
Logger.Initialize(tracingLevel: commandOptions.TracingLevel, logFilePath: logFilePath, traceSource: "credentials", commandOptions.AutoFlushLog);
|
||||
|
||||
// set up the host details and profile paths
|
||||
// set up the host details and profile paths
|
||||
var hostDetails = new HostDetails(
|
||||
name: "SqlTools Credentials Provider",
|
||||
profileId: "Microsoft.SqlTools.Credentials",
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.SqlTools.Hosting;
|
||||
using Microsoft.SqlTools.Hosting.Contracts;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Channel;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.Extensibility
|
||||
{
|
||||
public class ExtensionServiceHost : ServiceHostBase
|
||||
{
|
||||
|
||||
private ExtensibleServiceHostOptions options;
|
||||
private static bool isLoaded;
|
||||
public ExtensionServiceProvider serviceProvider;
|
||||
private List<IHostedService> initializedServices = new List<IHostedService>();
|
||||
|
||||
public ExtensionServiceHost(
|
||||
ExtensibleServiceHostOptions options
|
||||
) : base(new StdioServerChannel())
|
||||
{
|
||||
this.options = options;
|
||||
|
||||
this.Initialize();
|
||||
|
||||
// Start the service only after all request handlers are setup. This is vital
|
||||
// as otherwise the Initialize event can be lost - it's processed and discarded before the handler
|
||||
// is hooked up to receive the message
|
||||
this.Start().Wait();
|
||||
isLoaded = true;
|
||||
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
this.serviceProvider = ExtensionServiceProvider.CreateFromAssembliesInDirectory(options.ExtensionServiceAssemblyDirectory, options.ExtensionServiceAssemblyDllFileNames);
|
||||
var hostDetails = new HostDetails(
|
||||
name: options.HostName,
|
||||
profileId: options.HostProfileId,
|
||||
version: options.HostVersion);
|
||||
|
||||
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
|
||||
serviceProvider.RegisterSingleService(sqlToolsContext);
|
||||
serviceProvider.RegisterSingleService(this);
|
||||
this.InitializeHostedServices();
|
||||
this.InitializeRequestHandlers();
|
||||
}
|
||||
|
||||
private void InitializeRequestHandlers()
|
||||
{
|
||||
// Register the requests that this service host will handle
|
||||
this.SetRequestHandler(InitializeRequest.Type, this.HandleInitializeRequest);
|
||||
this.SetRequestHandler(ShutdownRequest.Type, this.HandleShutdownRequest);
|
||||
this.SetRequestHandler(VersionRequest.Type, this.HandleVersionRequest);
|
||||
}
|
||||
|
||||
private void InitializeHostedServices()
|
||||
{
|
||||
// Pre-register all services before initializing. This ensures that if one service wishes to reference
|
||||
// another one during initialization, it will be able to safely do so
|
||||
foreach (IHostedService service in this.serviceProvider.GetServices<IHostedService>())
|
||||
{
|
||||
if(IsServiceInitialized(service))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Logger.Verbose("Registering service: " + service.GetType());
|
||||
this.RegisterService(service);
|
||||
}
|
||||
|
||||
foreach (IHostedService service in this.serviceProvider.GetServices<IHostedService>())
|
||||
{
|
||||
if(IsServiceInitialized(service))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Logger.Verbose("Initializing service: " + service.GetType());
|
||||
// Initialize all hosted services, and register them in the service provider for their requested
|
||||
// service type. This ensures that when searching for the ConnectionService you can get it without
|
||||
// searching for an IHostedService of type ConnectionService
|
||||
this.InitializeService(service);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsServiceInitialized(IHostedService service)
|
||||
{
|
||||
return this.initializedServices.Any(s => s.GetType() == service.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate definition for the host shutdown event
|
||||
/// </summary>
|
||||
public delegate Task ShutdownCallback(object shutdownParams, RequestContext<object> shutdownRequestContext);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate definition for the host initialization event
|
||||
/// </summary>
|
||||
public delegate Task InitializeCallback(InitializeRequest startupParams, RequestContext<InitializeResult> requestContext);
|
||||
|
||||
private readonly List<ShutdownCallback> shutdownCallbacks = new List<ShutdownCallback>();
|
||||
|
||||
private readonly List<InitializeCallback> initializeCallbacks = new List<InitializeCallback>();
|
||||
|
||||
private readonly Version serviceVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new callback to be called when the shutdown request is submitted
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback to perform when a shutdown request is submitted</param>
|
||||
public void RegisterShutdownTask(ShutdownCallback callback)
|
||||
{
|
||||
shutdownCallbacks.Add(callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new method to be called when the initialize request is submitted
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback to perform when an initialize request is submitted</param>
|
||||
public void RegisterInitializeTask(InitializeCallback callback)
|
||||
{
|
||||
initializeCallbacks.Add(callback);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles the shutdown event for the Language Server
|
||||
/// </summary>
|
||||
private async Task HandleShutdownRequest(object shutdownParams, RequestContext<object> requestContext)
|
||||
{
|
||||
Logger.Write(TraceEventType.Information, "Service host is shutting down...");
|
||||
|
||||
// Call all the shutdown methods provided by the service components
|
||||
Task[] shutdownTasks = shutdownCallbacks.Select(t => t(shutdownParams, requestContext)).ToArray();
|
||||
TimeSpan shutdownTimeout = TimeSpan.FromSeconds(options.ShutdownTimeoutInSeconds);
|
||||
// shut down once all tasks are completed, or after the timeout expires, whichever comes first.
|
||||
await Task.WhenAny(Task.WhenAll(shutdownTasks), Task.Delay(shutdownTimeout)).ContinueWith(t => Environment.Exit(0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the initialization request
|
||||
/// </summary>
|
||||
private async Task HandleInitializeRequest(InitializeRequest initializeParams, RequestContext<InitializeResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Call all tasks that registered on the initialize request
|
||||
var initializeTasks = initializeCallbacks.Select(t => t(initializeParams, requestContext));
|
||||
await Task.WhenAll(initializeTasks);
|
||||
|
||||
// Send back what this server can do
|
||||
await requestContext.SendResult(
|
||||
new InitializeResult
|
||||
{
|
||||
Capabilities = options.ServerCapabilities
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the version request. Sends back the server version as result.
|
||||
/// </summary>
|
||||
private async Task HandleVersionRequest(object versionRequestParams, RequestContext<string> requestContext)
|
||||
{
|
||||
await requestContext.SendResult(serviceVersion.ToString());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads and initializes the services from the given assemblies
|
||||
/// </summary>
|
||||
/// <param name="assemblyPaths">path of the dll files</param>
|
||||
public void LoadAndIntializeServicesFromAssesmblies(string[] assemblyPaths)
|
||||
{
|
||||
this.serviceProvider.AddAssemblies<IHostedService>(options.ExtensionServiceAssemblyDirectory, assemblyPaths);
|
||||
this.InitializeHostedServices();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers and initializes the given service
|
||||
/// </summary>
|
||||
/// <param name="service">service to be initialized</param>
|
||||
protected void RegisterService(IHostedService service)
|
||||
{
|
||||
this.serviceProvider.RegisterSingleService(service.GetType(), service);
|
||||
|
||||
}
|
||||
|
||||
protected void InitializeService(IHostedService service)
|
||||
{
|
||||
service.InitializeService(this);
|
||||
this.initializedServices.Add(service);
|
||||
this.options.InitializeServiceCallback(this, service);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers and initializes the given services
|
||||
/// </summary>
|
||||
/// <param name="services">services to be initalized</param>
|
||||
public void RegisterAndInitializedServices(IEnumerable<IHostedService> services)
|
||||
{
|
||||
foreach (IHostedService service in services)
|
||||
{
|
||||
this.RegisterService(service);
|
||||
this.InitializeService(service);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register and initializes the given service
|
||||
/// </summary>
|
||||
/// <param name="service">service to be initialized</param>
|
||||
public void RegisterAndInitializeService(IHostedService service)
|
||||
{
|
||||
this.RegisterService(service);
|
||||
this.InitializeService(service);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class ExtensibleServiceHostOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The folder where the extension service assemblies are located. By default it is
|
||||
/// the folder where the current server assembly is located.
|
||||
/// </summary>
|
||||
public string ExtensionServiceAssemblyDirectory { get; set; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
/// <summary>
|
||||
/// The dlls that contain the extension services.
|
||||
/// </summary>
|
||||
public string[] ExtensionServiceAssemblyDllFileNames { get; set; } = new string[0];
|
||||
|
||||
/// <summary>
|
||||
/// Host name for the services.
|
||||
/// </summary>
|
||||
public string HostName { get; set; } = HostDetails.DefaultHostName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile ID of the host, used to determine the
|
||||
/// host-specific profile path.
|
||||
/// </summary>
|
||||
public string HostProfileId { get; set; } = HostDetails.DefaultHostProfileId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of the host.
|
||||
/// </summary>
|
||||
public Version HostVersion { get; set; } = HostDetails.DefaultHostVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Data protocol capabilities that the server supports.
|
||||
/// </summary>
|
||||
public ServerCapabilities ServerCapabilities { get; set; } = new ServerCapabilities
|
||||
{
|
||||
DefinitionProvider = false,
|
||||
ReferencesProvider = false,
|
||||
DocumentFormattingProvider = false,
|
||||
DocumentRangeFormattingProvider = false,
|
||||
DocumentHighlightProvider = false,
|
||||
HoverProvider = false
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Timeout in seconds for the shutdown request. Default is 120 seconds.
|
||||
/// </summary>
|
||||
public int ShutdownTimeoutInSeconds { get; set; } = 120;
|
||||
|
||||
public delegate void InitializeService(ExtensionServiceHost serviceHost, IHostedService service);
|
||||
|
||||
/// <summary>
|
||||
/// Service initialization callback. The caller must define this callback to initialize the service.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public InitializeService InitializeServiceCallback { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -119,16 +119,89 @@ namespace Microsoft.SqlTools.Extensibility
|
||||
/// <summary>
|
||||
/// Merges in new assemblies to the existing container configuration.
|
||||
/// </summary>
|
||||
public void AddAssembliesToConfiguration(IEnumerable<Assembly> assemblies)
|
||||
/// <typeparam name="T">Type of the service present in the assemblies</typeparam>
|
||||
public void AddAssembliesToConfiguration<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
Validate.IsNotNull(nameof(assemblies), assemblies);
|
||||
var previousConfig = config;
|
||||
this.config = conventions => {
|
||||
this.config = conventions =>
|
||||
{
|
||||
// Chain in the existing configuration function's result, then include additional
|
||||
// assemblies
|
||||
ContainerConfiguration containerConfig = previousConfig(conventions);
|
||||
return containerConfig.WithAssemblies(assemblies, conventions);
|
||||
};
|
||||
ExtensionStore store = new ExtensionStore(typeof(T), config);
|
||||
|
||||
// If the service type is already registered, replace the existing registration with the new one
|
||||
if (this.services.ContainsKey(typeof(T)))
|
||||
{
|
||||
this.services[typeof(T)] = () => store.GetExports<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Register<T>(() => store.GetExports<T>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a service provider by loading a set of named assemblies, expected to be <paramref name="directory"/>
|
||||
/// </summary>
|
||||
/// <param name="directory">Directory to search for included assemblies</param>
|
||||
/// <param name="inclusionList">full DLL names, case insensitive, of assemblies to include</param>
|
||||
/// <returns><see cref="ExtensionServiceProvider"/> instance</returns>
|
||||
public static ExtensionServiceProvider CreateFromAssembliesInDirectory(string directory, IList<string> inclusionList)
|
||||
{
|
||||
Logger.Verbose("Loading service assemblies from ..."+ directory);
|
||||
var assemblyPaths = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly);
|
||||
|
||||
List<Assembly> assemblies = LoadAssemblies(directory, inclusionList);
|
||||
return Create(assemblies);
|
||||
}
|
||||
|
||||
public void AddAssemblies<T>(string directory, IList<string> inclusionList)
|
||||
{
|
||||
this.AddAssembliesToConfiguration<T>(LoadAssemblies(directory, inclusionList));
|
||||
}
|
||||
|
||||
private static List<Assembly> LoadAssemblies(string directory, IList<string> inclusionList)
|
||||
{
|
||||
Logger.Verbose("Loading service assemblies from ..."+ directory);
|
||||
//AssemblyLoadContext context = new AssemblyLoader(directory);
|
||||
var assemblyPaths = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly);
|
||||
|
||||
List<Assembly> assemblies = new List<Assembly>();
|
||||
foreach (var path in assemblyPaths)
|
||||
{
|
||||
// skip DLL files not in inclusion list
|
||||
bool isInList = false;
|
||||
foreach (var item in inclusionList)
|
||||
{
|
||||
if (path.EndsWith(item, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isInList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Logger.Verbose("Loading service assembly: " + path);
|
||||
assemblies.Add(AssemblyLoadContext.Default.LoadFromAssemblyPath(path));
|
||||
Logger.Verbose("Loaded service assembly: " + path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// we expect exceptions trying to scan all DLLs since directory contains native libraries
|
||||
Logger.Error(ex);
|
||||
}
|
||||
}
|
||||
return assemblies;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -193,7 +266,7 @@ namespace Microsoft.SqlTools.Extensibility
|
||||
{
|
||||
// Define exports as matching a parent type, export as that parent type
|
||||
var builder = new ConventionBuilder();
|
||||
builder.ForTypesDerivedFrom(contractType).Export(exportConventionBuilder => exportConventionBuilder.AsContractType(contractType));
|
||||
builder.ForTypesDerivedFrom(contractType).Export(exportConventionBuilder => exportConventionBuilder.AsContractType(contractType));
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
135
src/Microsoft.SqlTools.Hosting/README.md
Normal file
135
src/Microsoft.SqlTools.Hosting/README.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# SqlTools.Hosting
|
||||
|
||||
## Description
|
||||
This library contains the necessary classes for implementing an Azure Data Studio [language server](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide). It provides a simple and easy-to-use API for handling JSON-RPC requests and responses, and supports adding LSP messages and notifications.
|
||||
|
||||
## Usage
|
||||
Example of using extension service host to implement a JSON rpc server and registering a service with it.
|
||||
|
||||
```cs
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using Microsoft.SqlTools.Extensibility;
|
||||
using Microsoft.SqlTools.Hosting;
|
||||
|
||||
namespace Microsoft.SqlTools.SampleService
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private const string ServiceName = "MicrosoftSqlToolsSampleService.exe";
|
||||
|
||||
internal static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
// reading command-line arguments
|
||||
CommandOptions commandOptions = new CommandOptions(args, ServiceName);
|
||||
|
||||
|
||||
// Using the command-line arguments to initialize the logger included in the library
|
||||
string logFilePath = "MicrosoftSqlToolsSampleService";
|
||||
if (!string.IsNullOrWhiteSpace(commandOptions.LogFilePath))
|
||||
{
|
||||
logFilePath = Path.Combine(commandOptions.LogFilePath, logFilePath);
|
||||
} else
|
||||
{
|
||||
logFilePath = Logger.GenerateLogFilePath(logFilePath);
|
||||
|
||||
}
|
||||
|
||||
Logger.Initialize(
|
||||
tracingLevel: SourceLevels.Verbose,
|
||||
logFilePath: logFilePath, "MicrosoftSqlToolsSampleService",
|
||||
commandOptions.AutoFlushLog
|
||||
);
|
||||
|
||||
Logger.Verbose("Starting SqlTools Sample Services.....");
|
||||
|
||||
// Setting up the options for the extension service host
|
||||
ExtensibleServiceHostOptions serverOptions = new ExtensibleServiceHostOptions()
|
||||
{
|
||||
// Name of the server
|
||||
HostName = "Sample Server",
|
||||
// Unique identifier for the server
|
||||
HostProfileId = "Microsoft.SqlTools.SampleServer",
|
||||
// Version of the server
|
||||
HostVersion = new Version(1, 0, 0, 0),
|
||||
// Directory where the service assemblies are located
|
||||
ExtensionServiceAssemblyDirectory = Path.GetDirectoryName(typeof(Program).Assembly.Location),
|
||||
// Names of the service assemblies
|
||||
ExtensionServiceAssemblyDllFileNames = new string[] {
|
||||
"Microsoft.SqlTools.SampleServer.Service1MEF.dll",
|
||||
}
|
||||
};
|
||||
|
||||
// Creating the extension service host
|
||||
ExtensionServiceHost serviceHost = new ExtensionServiceHost(serverOptions);
|
||||
|
||||
// Registering the service with the extension service host
|
||||
serviceHost.RegisterAndInitializedServices(SampleService.Instance);
|
||||
serviceHost.RegisterAndInitializeService(SampleService.Instance);
|
||||
|
||||
// Adding more assemblies to the extension service host
|
||||
serviceHost.LoadAndIntializeServicesFromAssesmblies(
|
||||
new string[] {
|
||||
"Microsoft.SqlTools.SampleServer.Services2MEF.dll"
|
||||
}
|
||||
);
|
||||
|
||||
serviceHost.WaitForExit();
|
||||
|
||||
Logger.Verbose("SqlTools Sample Services stopped.");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Write(TraceEventType.Error, string.Format("An unhandled exception occurred: {0}", e));
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Implementing a service for Extension Service Host for MEF based consumption.
|
||||
|
||||
```cs
|
||||
namespace Microsoft.SqlTools.SampleServer.Service1MEF
|
||||
{
|
||||
[Export(typeof(IHostedService))] // This is required for MEF to discover the service
|
||||
public class SampleServiceMEF1 : IHostedService
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```cs
|
||||
namespace Microsoft.SqlTools.SampleServer.Service2MEF
|
||||
{
|
||||
[Export(typeof(IHostedService))] // This is required for MEF to discover the service
|
||||
public class SampleServiceMEF2 : IHostedService
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Implementing a service for direct consumption.
|
||||
```cs
|
||||
namespace Microsoft.SqlTools.SampleServer.Service
|
||||
{
|
||||
public class SampleService : IHostedService
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
The library has been tested with and is compatible with following other JSON-RPC library:
|
||||
|
||||
* [sqlops-dataprotocolclient](https://github.com/microsoft/sqlops-dataprotocolclient)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.SqlTools.Hosting.Utility
|
||||
namespace Microsoft.SqlTools.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// The command-line options helper class.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.SqlTools.Hosting.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
var serviceProvider = (ExtensionServiceProvider)ServiceHostInstance.ServiceProvider;
|
||||
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(param.AssemblyPath);
|
||||
var assemblies = new Assembly[] { assembly };
|
||||
serviceProvider.AddAssembliesToConfiguration(assemblies);
|
||||
serviceProvider.AddAssembliesToConfiguration<ICompletionExtension>(assemblies);
|
||||
foreach (var ext in serviceProvider.GetServices<ICompletionExtension>())
|
||||
{
|
||||
var cancellationTokenSource = new CancellationTokenSource(ExtensionLoadingTimeout);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.SqlTools.Hosting.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using NUnit.Framework;
|
||||
|
||||
using CredSR = Microsoft.SqlTools.Credentials.SR;
|
||||
|
||||
Reference in New Issue
Block a user