// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.TaskServices; using System; using System.Collections.Concurrent; using System.Data.SqlClient; using System.Threading.Tasks; namespace Microsoft.SqlTools.ServiceLayer.DacFx { /// /// Main class for DacFx service /// class DacFxService { private static ConnectionService connectionService = null; private SqlTaskManager sqlTaskManagerInstance = null; private static readonly Lazy instance = new Lazy(() => new DacFxService()); private readonly Lazy> operations = new Lazy>(() => new ConcurrentDictionary()); /// /// Gets the singleton instance object /// public static DacFxService Instance { get { return instance.Value; } } /// /// Initializes the service instance /// /// public void InitializeService(ServiceHost serviceHost) { serviceHost.SetRequestHandler(ExportRequest.Type, this.HandleExportRequest); serviceHost.SetRequestHandler(ImportRequest.Type, this.HandleImportRequest); serviceHost.SetRequestHandler(ExtractRequest.Type, this.HandleExtractRequest); serviceHost.SetRequestHandler(DeployRequest.Type, this.HandleDeployRequest); serviceHost.SetRequestHandler(GenerateDeployScriptRequest.Type, this.HandleGenerateDeployScriptRequest); serviceHost.SetRequestHandler(GenerateDeployPlanRequest.Type, this.HandleGenerateDeployPlanRequest); } /// /// The collection of active operations /// internal ConcurrentDictionary ActiveOperations => operations.Value; /// /// Handles request to export a bacpac /// /// public async Task HandleExportRequest(ExportParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { ExportOperation operation = new ExportOperation(parameters, connInfo); await ExecuteOperation(operation, parameters, SR.ExportBacpacTaskName, requestContext); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handles request to import a bacpac /// /// public async Task HandleImportRequest(ImportParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { ImportOperation operation = new ImportOperation(parameters, connInfo); await ExecuteOperation(operation, parameters, SR.ImportBacpacTaskName, requestContext); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handles request to extract a dacpac /// /// public async Task HandleExtractRequest(ExtractParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { ExtractOperation operation = new ExtractOperation(parameters, connInfo); await ExecuteOperation(operation, parameters, SR.ExtractDacpacTaskName, requestContext); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handles request to deploy a dacpac /// /// public async Task HandleDeployRequest(DeployParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { DeployOperation operation = new DeployOperation(parameters, connInfo); await ExecuteOperation(operation, parameters, SR.DeployDacpacTaskName, requestContext); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handles request to generate deploy script /// /// public async Task HandleGenerateDeployScriptRequest(GenerateDeployScriptParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { GenerateDeployScriptOperation operation = new GenerateDeployScriptOperation(parameters, connInfo); SqlTask sqlTask = null; TaskMetadata metadata = new TaskMetadata(); metadata.TaskOperation = operation; metadata.TaskExecutionMode = parameters.TaskExecutionMode; metadata.ServerName = connInfo.ConnectionDetails.ServerName; metadata.DatabaseName = parameters.DatabaseName; metadata.Name = SR.GenerateScriptTaskName; sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); await requestContext.SendResult(new DacFxResult() { OperationId = operation.OperationId, Success = true, ErrorMessage = string.Empty }); } } catch (Exception e) { await requestContext.SendError(e); } } /// /// Handles request to generate deploy plan /// /// public async Task HandleGenerateDeployPlanRequest(GenerateDeployPlanParams parameters, RequestContext requestContext) { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); if (connInfo != null) { GenerateDeployPlanOperation operation = new GenerateDeployPlanOperation(parameters, connInfo); operation.Execute(parameters.TaskExecutionMode); await requestContext.SendResult(new GenerateDeployPlanRequestResult() { OperationId = operation.OperationId, Success = true, ErrorMessage = string.Empty, Report = operation.DeployReport }); } } catch (Exception e) { await requestContext.SendError(e); } } private async Task ExecuteOperation(DacFxOperation operation, DacFxParams parameters, string taskName, RequestContext requestContext) { SqlTask sqlTask = null; TaskMetadata metadata = TaskMetadata.Create(parameters, taskName, operation, ConnectionServiceInstance); // put appropriate database name since connection passed was to master metadata.DatabaseName = parameters.DatabaseName; sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); await requestContext.SendResult(new DacFxResult() { OperationId = operation.OperationId, Success = true, ErrorMessage = string.Empty }); } private SqlTaskManager SqlTaskManagerInstance { get { if (sqlTaskManagerInstance == null) { sqlTaskManagerInstance = SqlTaskManager.Instance; } return sqlTaskManagerInstance; } set { sqlTaskManagerInstance = value; } } /// /// Internal for testing purposes only /// internal static ConnectionService ConnectionServiceInstance { get { if (connectionService == null) { connectionService = ConnectionService.Instance; } return connectionService; } set { connectionService = value; } } /// /// For testing purpose only /// /// internal void PerformOperation(DacFxOperation operation, TaskExecutionMode taskExecutionMode) { operation.Execute(taskExecutionMode); } } }