Files
sqltoolsservice/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
Aleksei Guzev bcc1f2a486 Add AQL Assessment service (#946)
[SQL Assessment API](https://docs.microsoft.com/en-us/sql/sql-assessment-api/sql-assessment-api-overview) provides a mechanism to evaluate the configuration
of SQL Server for best practices. SQL Assessment API gives a list
of recommended actions to improve SQL Server performance or security.

The SQL Assessment service is used by the expected SQL Assessment
feature of Azure Data Studio. 

SqlAssessmentService forwards JSONRPC calls to SQL Assessment engine
and wraps results as a response.

`assessment/getAssessmentItems` returns a set of checks 
applicable to a given target.

`assessment/invoke` returns a set of recommendations
for improving SQL Server instance or database configurations. 

`assessment/generateScript` returns a T-SQL script for storing
an assessment result set to a SQL data table.
2020-04-24 10:52:55 +03:00

177 lines
8.3 KiB
C#

//
// 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.Threading.Tasks;
using Microsoft.SqlTools.Credentials;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.Agent;
using Microsoft.SqlTools.ServiceLayer.Cms;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.DacFx;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
using Microsoft.SqlTools.ServiceLayer.EditData;
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
using Microsoft.SqlTools.ServiceLayer.Metadata;
using Microsoft.SqlTools.ServiceLayer.Profiler;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
using Microsoft.SqlTools.ServiceLayer.Scripting;
using Microsoft.SqlTools.ServiceLayer.Security;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Workspace;
namespace Microsoft.SqlTools.ServiceLayer
{
/// <summary>
/// Provides support for starting up a service host. This is a common responsibility
/// for both the main service program and test driver that interacts with it
/// </summary>
public static class HostLoader
{
private static object lockObject = new object();
private static bool isLoaded;
internal static ServiceHost CreateAndStartServiceHost(SqlToolsContext sqlToolsContext)
{
ServiceHost serviceHost = ServiceHost.Instance;
lock (lockObject)
{
if (!isLoaded)
{
// Grab the instance of the service host
serviceHost.Initialize();
InitializeRequestHandlersAndServices(serviceHost, sqlToolsContext);
// 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
serviceHost.Start().Wait();
isLoaded = true;
}
}
return serviceHost;
}
private static void InitializeRequestHandlersAndServices(ServiceHost serviceHost, SqlToolsContext sqlToolsContext)
{
// Load extension provider, which currently finds all exports in current DLL. Can be changed to find based
// on directory or assembly list quite easily in the future
ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
serviceProvider.RegisterSingleService(sqlToolsContext);
serviceProvider.RegisterSingleService(serviceHost);
// Initialize and register singleton services so they're accessible for any MEF service. In the future, these
// could be updated to be IComposableServices, which would avoid the requirement to define a singleton instance
// and instead have MEF handle discovery & loading
WorkspaceService<SqlToolsSettings>.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(WorkspaceService<SqlToolsSettings>.Instance);
LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext);
serviceProvider.RegisterSingleService(LanguageService.Instance);
ConnectionService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ConnectionService.Instance);
CredentialService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(CredentialService.Instance);
QueryExecutionService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(QueryExecutionService.Instance);
EditDataService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(EditDataService.Instance);
MetadataService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(MetadataService.Instance);
ScriptingService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ScriptingService.Instance);
AdminService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(AdminService.Instance);
AgentService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(AgentService.Instance);
DisasterRecoveryService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(DisasterRecoveryService.Instance);
FileBrowserService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(FileBrowserService.Instance);
ProfilerService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ProfilerService.Instance);
SecurityService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(SecurityService.Instance);
DacFxService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(DacFxService.Instance);
CmsService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(CmsService.Instance);
SchemaCompare.SchemaCompareService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(SchemaCompareService.Instance);
ServerConfigService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ServerConfigService.Instance);
ExternalLanguageService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(ExternalLanguageService.Instance);
SqlAssessmentService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(SqlAssessmentService.Instance);
InitializeHostedServices(serviceProvider, serviceHost);
serviceHost.ServiceProvider = serviceProvider;
serviceHost.InitializeRequestHandlers();
}
/// <summary>
/// Internal to support testing. Initializes <see cref="IHostedService"/> instances in the service,
/// and registers them for their preferred service type
/// </summary>
internal static void InitializeHostedServices(RegisteredServiceProvider provider, IProtocolEndpoint host)
{
// 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 provider.GetServices<IHostedService>())
{
provider.RegisterSingleService(service.ServiceType, service);
}
ServiceHost serviceHost = host as ServiceHost;
foreach (IHostedService service in provider.GetServices<IHostedService>())
{
// 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
service.InitializeService(host);
IDisposable disposable = service as IDisposable;
if (serviceHost != null && disposable != null)
{
serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) =>
{
disposable.Dispose();
await Task.FromResult(0);
});
}
}
}
}
}