public override bool OnDeactivate() { if (Wizard.MovingNext) { var selectedVersion = GetSelectedVersion(); var useLegacyProvider = selectedVersion != null ? RuntimeVersion.RequiresLegacyProvider(selectedVersion) : OptionsDesignerInfo.UseLegacyProviderDefault; if (Wizard.ModelBuilderSettings.UseLegacyProvider != useLegacyProvider) { Wizard.InvalidateFollowingPages(); } Wizard.ModelBuilderSettings.UseLegacyProvider = useLegacyProvider; Wizard.ModelBuilderSettings.TargetSchemaVersion = RuntimeVersion.GetTargetSchemaVersion( selectedVersion, NetFrameworkVersioningHelper.TargetNetFrameworkVersion(Wizard.Project, ServiceProvider)); VsUtils.EnsureProvider( Wizard.ModelBuilderSettings.RuntimeProviderInvariantName, Wizard.ModelBuilderSettings.UseLegacyProvider, Wizard.Project, ServiceProvider); Wizard.ModelBuilderSettings.ProviderManifestToken = DatabaseGenerationEngine.GetProviderManifestTokenConnected( DependencyResolver.Instance, Wizard.ModelBuilderSettings.RuntimeProviderInvariantName, Wizard.ModelBuilderSettings.DesignTimeConnectionString); } return(base.OnDeactivate()); }
public override void OnActivated() { base.OnActivated(); _onWorkflowCleanup = false; Debug.Assert( !Wizard.MovingNext || _workflowInstance == null, "Possible memory leak: We should have destroyed the old workflow instance when activating WizardPageDbGenSummary"); if (_workflowInstance == null) { if (LocalDataUtil.IsSqlMobileConnectionString(Wizard.ModelBuilderSettings.DesignTimeProviderInvariantName)) { _ddlFileExtension = DatabaseGenerationEngine._sqlceFileExtension; } else { _ddlFileExtension = DatabaseGenerationEngine._ddlFileExtension; } // Add in the DbConfig page before if we have found a connection if (Wizard.Mode == ModelBuilderWizardForm.WizardMode.PerformDBGenSummaryOnly && _addedDbConfigPage == false) { Wizard.InsertPageBefore(Id, new WizardPageDbConfig(Wizard)); _addedDbConfigPage = true; } // Display the default path for the DDL var artifactProjectItem = VsUtils.GetProjectItemForDocument( Wizard.ModelBuilderSettings.Artifact.Uri.LocalPath, PackageManager.Package); if (artifactProjectItem != null) { txtSaveDdlAs.Text = DatabaseGenerationEngine.CreateDefaultDdlFileName(artifactProjectItem) + _ddlFileExtension; } // Disable all buttons except for Previous and Cancel Wizard.EnableButton(ButtonType.Previous, true); Wizard.EnableButton(ButtonType.Next, false); Wizard.EnableButton(ButtonType.Finish, false); Wizard.EnableButton(ButtonType.Cancel, true); // Display a status message ShowStatus(Properties.Resources.DbGenSummary_StatusDeterminingDDL); // Extract the XML from the EDMX file and convert it into an EdmItemCollection for the workflow EdmItemCollection edm = null; using (new VsUtils.HourglassHelper()) { IList <EdmSchemaError> schemaErrors; edm = Wizard.ModelBuilderSettings.Artifact.GetEdmItemCollectionFromArtifact(out schemaErrors); Debug.Assert( edm != null && schemaErrors.Count == 0, "EdmItemCollection schema errors found; we should have performed validation on the EdmItemCollection before instantiating the wizard."); } var existingSsdl = Wizard.ModelBuilderSettings.Artifact.GetSsdlAsString(); var existingMsl = Wizard.ModelBuilderSettings.Artifact.GetMslAsString(); // Attempt to get the workflow path, template path, and database schema name from the artifact. If we don't find them, we'll use defaults. var workflowPath = DatabaseGenerationEngine.GetWorkflowPathFromArtifact(Wizard.ModelBuilderSettings.Artifact); var templatePath = DatabaseGenerationEngine.GetTemplatePathFromArtifact(Wizard.ModelBuilderSettings.Artifact); var databaseSchemaName = DatabaseGenerationEngine.GetDatabaseSchemaNameFromArtifact(Wizard.ModelBuilderSettings.Artifact); // Save off the SynchronizationContext so we can post methods to the UI event queue when // responding to workflow events (since they are executed in a separate thread) _synchronizationContext = SynchronizationContext.Current; // Invoke the Pipeline/Workflow. The Workflow engine will automatically wrap this in a background thread try { using (new VsUtils.HourglassHelper()) { var resolvedWorkflowFileInfo = DatabaseGenerationEngine.ResolveAndValidateWorkflowPath( Wizard.Project, workflowPath); var resolvedDefaultPath = VsUtils.ResolvePathWithMacro( null, DatabaseGenerationEngine.DefaultWorkflowPath, new Dictionary <string, string> { { ExtensibleFileManager.EFTOOLS_USER_MACRONAME, ExtensibleFileManager.UserEFToolsDir.FullName }, { ExtensibleFileManager.EFTOOLS_VS_MACRONAME, ExtensibleFileManager.VSEFToolsDir.FullName } }); // Display a security warning if the workflow path specified is different from the default if (!resolvedWorkflowFileInfo.FullName.Equals( Path.GetFullPath(resolvedDefaultPath), StringComparison.OrdinalIgnoreCase)) { var displayCustomWorkflowWarning = true; try { var customWorkflowWarningString = EdmUtils.GetUserSetting(RegKeyNameCustomWorkflowWarning); if (false == String.IsNullOrEmpty(customWorkflowWarningString) && false == Boolean.TryParse(customWorkflowWarningString, out displayCustomWorkflowWarning)) { displayCustomWorkflowWarning = true; } if (displayCustomWorkflowWarning) { var cancelledDuringCustomWorkflowWarning = DismissableWarningDialog .ShowWarningDialogAndSaveDismissOption( Resources.DatabaseCreation_CustomWorkflowWarningTitle, Resources.DatabaseCreation_WarningCustomWorkflow, RegKeyNameCustomWorkflowWarning, DismissableWarningDialog.ButtonMode.OkCancel); if (cancelledDuringCustomWorkflowWarning) { HandleError( String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_CustomWorkflowCancelled, resolvedWorkflowFileInfo.FullName), false); return; } } } catch (SecurityException e) { // We should at least alert the user of why this is failing so they can take steps to fix it. VsUtils.ShowMessageBox( Services.ServiceProvider, String.Format( CultureInfo.CurrentCulture, Resources.ErrorReadingWritingUserSetting, RegKeyNameCustomWorkflowWarning, e.Message), OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING); } } _workflowInstance = DatabaseGenerationEngine.CreateDatabaseScriptGenerationWorkflow( _synchronizationContext, Wizard.Project, Wizard.ModelBuilderSettings.Artifact.Uri.LocalPath, resolvedWorkflowFileInfo, templatePath, edm, existingSsdl, existingMsl, databaseSchemaName, Wizard.ModelBuilderSettings.InitialCatalog, Wizard.ModelBuilderSettings.RuntimeProviderInvariantName, Wizard.ModelBuilderSettings.AppConfigConnectionString, Wizard.ModelBuilderSettings.ProviderManifestToken, Wizard.ModelBuilderSettings.Artifact.SchemaVersion, _workflowInstance_WorkflowCompleted, _workflowInstance_UnhandledException); } Wizard.ModelBuilderSettings.WorkflowInstance = _workflowInstance; _workflowInstance.Run(); } catch (Exception e) { HandleError(e.Message, true); if (_workflowInstance != null) { CleanupWorkflow(); } } } }
internal override bool OnWizardFinish() { if (Wizard.ModelBuilderSettings.DdlStringReader != null) { // Make sure that the DDL filename is not null if (String.IsNullOrEmpty(txtSaveDdlAs.Text)) { VsUtils.ShowErrorDialog(Properties.Resources.ErrorDdlFileNameIsNull); return(false); } // Resolve the project URI Uri projectUri = null; bool projectHasFilename; var projectFullName = VsUtils.GetProjectPathWithName(Wizard.Project, out projectHasFilename); try { if (false == Uri.TryCreate(projectFullName, UriKind.Absolute, out projectUri) || projectUri == null) { VsUtils.ShowErrorDialog( String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorResolvingProjectFile, projectFullName)); return(false); } } catch (UriFormatException) { VsUtils.ShowErrorDialog( String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorResolvingProjectFile, projectFullName)); } // Attempt to create a URI from the DDL path, either relative to the project URI or absolute. Uri ddlUri = null; try { if (false == Uri.TryCreate(projectUri, txtSaveDdlAs.Text, out ddlUri) || ddlUri == null) { VsUtils.ShowErrorDialog( String.Format( CultureInfo.CurrentCulture, Properties.Resources.ErrorResolvingDdlFileNameException, txtSaveDdlAs.Text)); return(false); } } catch (UriFormatException) { VsUtils.ShowErrorDialog( String.Format( CultureInfo.CurrentCulture, Properties.Resources.ErrorResolvingDdlFileNameException, txtSaveDdlAs.Text)); } var ddlFilePath = ddlUri.LocalPath; // Validate the file name try { var ddlFileName = Path.GetFileName(ddlFilePath); if (String.IsNullOrEmpty(ddlFileName)) { VsUtils.ShowErrorDialog( String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorDdlPathNotFile, ddlFilePath)); return(false); } if (!VsUtils.IsValidFileName(ddlFileName)) { VsUtils.ShowErrorDialog(String.Format(CultureInfo.CurrentCulture, Resources.ErrorNonValidFileName, ddlFilePath)); return(false); } } catch (ArgumentException) { VsUtils.ShowErrorDialog( String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorResolvingDdlFileNameException, ddlFilePath)); return(false); } // Add ".sql" if the extension is not already .sql if (!Path.GetExtension(ddlFilePath).Equals(_ddlFileExtension, StringComparison.OrdinalIgnoreCase)) { ddlFilePath += _ddlFileExtension; } // Now we should have a valid, non-null filename Debug.Assert( !String.IsNullOrEmpty(ddlFilePath), "DDL filename should either be not null or we should have handled an exception before continuing..."); if (String.IsNullOrEmpty(ddlFilePath)) { VsUtils.ShowErrorDialog(Properties.Resources.ErrorDdlFileNameIsNull); return(false); } // If the parent directory does not exist, then we do not proceed try { var fileInfo = new FileInfo(ddlFilePath); var parentDirInfo = fileInfo.Directory; if (parentDirInfo != null) { if (false == parentDirInfo.Exists) { VsUtils.ShowErrorDialog( String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorNoDdlParentDir, ddlFilePath)); return(false); } } } catch (Exception e) { // various exceptions could occur here, such as PathTooLong or Security. In this case we will display an error. VsUtils.ShowErrorDialog( String.Format( CultureInfo.CurrentCulture, Properties.Resources.ErrorCouldNotParseDdlFileName, ddlFilePath, e.Message)); return(false); } // Display the DDL Overwrite Warning Dialog if (File.Exists(ddlFilePath)) { var displayDdlOverwriteWarning = true; try { var ddlOverwriteWarningString = EdmUtils.GetUserSetting(RegKeyNameDdlOverwriteWarning); if (false == String.IsNullOrEmpty(ddlOverwriteWarningString) && false == Boolean.TryParse(ddlOverwriteWarningString, out displayDdlOverwriteWarning)) { displayDdlOverwriteWarning = true; } if (displayDdlOverwriteWarning) { var cancelledDuringOverwriteDdl = DismissableWarningDialog.ShowWarningDialogAndSaveDismissOption( Resources.DatabaseCreation_DDLOverwriteWarningTitle, String.Format(CultureInfo.CurrentCulture, Resources.DatabaseCreation_WarningOverwriteDdl, ddlFilePath), RegKeyNameDdlOverwriteWarning, DismissableWarningDialog.ButtonMode.YesNo); if (cancelledDuringOverwriteDdl) { return(false); } } } catch (SecurityException e) { // We should at least alert the user of why this is failing so they can take steps to fix it. VsUtils.ShowMessageBox( Services.ServiceProvider, String.Format( CultureInfo.CurrentCulture, Resources.ErrorReadingWritingUserSetting, RegKeyNameDdlOverwriteWarning, e.Message), OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING); } } // At this point we will save off the DDL Filename into the wizard settings Wizard.ModelBuilderSettings.DdlFileName = ddlFilePath; } if ((Wizard.ModelBuilderSettings.SsdlStringReader != null || Wizard.ModelBuilderSettings.MslStringReader != null) && (Wizard.ModelBuilderSettings.Artifact != null) && (Wizard.ModelBuilderSettings.Artifact.StorageModel() != null) && (!Wizard.ModelBuilderSettings.Artifact.StorageModel().IsEmpty)) { // Display the SSDL/MSL Overwrite Warning Dialog var displayEdmxOverwriteWarning = true; try { var edmxOverwriteWarningString = EdmUtils.GetUserSetting(RegKeyNameEdmxOverwriteWarning); if (false == String.IsNullOrEmpty(edmxOverwriteWarningString) && false == Boolean.TryParse(edmxOverwriteWarningString, out displayEdmxOverwriteWarning)) { displayEdmxOverwriteWarning = true; } if (displayEdmxOverwriteWarning) { var cancelledDuringOverwriteSsdl = DismissableWarningDialog.ShowWarningDialogAndSaveDismissOption( Resources.DatabaseCreation_EdmxOverwriteWarningTitle, Resources.DatabaseCreation_WarningOverwriteMappings, RegKeyNameEdmxOverwriteWarning, DismissableWarningDialog.ButtonMode.YesNo); if (cancelledDuringOverwriteSsdl) { return(false); } } } catch (SecurityException e) { // We should at least alert the user of why this is failing so they can take steps to fix it. VsUtils.ShowMessageBox( Services.ServiceProvider, String.Format( CultureInfo.CurrentCulture, Resources.ErrorReadingWritingUserSetting, RegKeyNameEdmxOverwriteWarning, e.Message), OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING); } } using (new VsUtils.HourglassHelper()) { // Now we output the DDL, update app/web.config, update the edmx, and open the SQL file that gets produced return(DatabaseGenerationEngine.UpdateEdmxAndEnvironment(Wizard.ModelBuilderSettings)); } }
internal void TestPipeline( string testName, EdmItemCollection csdlInput, string workflowFilePath, Version versionOfCsdl, Func <WorkflowApplicationCompletedEventArgs, object> postInvokeCallback) { const string existingMsl = "<Mapping Space='C-S' xmlns='http://schemas.microsoft.com/ado/2008/09/mapping/cs'>" + " <EntityContainerMapping StorageEntityContainer='Model1StoreContainer' CdmEntityContainer='Model1Container' />" + "</Mapping>"; const string existingSsdl = "<Schema Namespace='Store' Alias='Self' Provider='System.Data.SqlClient' ProviderManifestToken='2005' xmlns='http://schemas.microsoft.com/ado/2006/04/edm/ssdl' />"; Exception savedException = null; var workflowCompleted = new AutoResetEvent(false); var completedHandler = new Action <WorkflowApplicationCompletedEventArgs>( e => { try { var result = (string)postInvokeCallback(e); Assert.AreEqual( TestUtils.LoadEmbeddedResource("EFDesigner.InProcTests.Baselines." + testName + ".bsl"), result); } catch (Exception ex) { // save off the exception, return out of the completion handler. If we throw here // the wrong thread will catch the exception savedException = ex; } finally { workflowCompleted.Set(); } } ); var unhandledExceptionHandler = new Func <WorkflowApplicationUnhandledExceptionEventArgs, UnhandledExceptionAction>( e => { if (e.UnhandledException != null) { Console.WriteLine(e.UnhandledException); savedException = e.UnhandledException; } workflowCompleted.Set(); return(UnhandledExceptionAction.Terminate); } ); var resolvedWorkflowFileInfo = DatabaseGenerationEngine.ResolveAndValidateWorkflowPath(null, workflowFilePath); var workflowInstance = DatabaseGenerationEngine.CreateDatabaseScriptGenerationWorkflow( null, null, null, resolvedWorkflowFileInfo, "$(VSEFTools)\\DBGen\\SSDLToSQL10.tt", csdlInput, existingSsdl, existingMsl, "dbo", "TestDb", "System.Data.SqlClient", null, "2005", versionOfCsdl, completedHandler, unhandledExceptionHandler); // Kick off the workflow workflowInstance.Run(); // Block this thread until the AutoResetEvent receives a signal for synchronous behavior (just in case) workflowCompleted.WaitOne(); // Check to see if an exception was set, if so, throw it so the test framework can handle it if (savedException != null) { throw savedException; } }
/// <summary> /// Process a T4 template using Visual Studio's text templating service, given a path that could contain macros (i.e. "$(DevEnvDir)\..."). /// NOTE: Template paths that are not files or are UNC paths are not allowed /// </summary> /// <param name="templatePath">Template's file path which may contain project-based macros</param> /// <returns>The output of processing the template.</returns> protected string ProcessTemplate(string templatePath) { // Attempt to resolve the full template path if it contains any macros, using // the edmx path to get the project and using the project's defined macros. Project project = null; if (!String.IsNullOrEmpty(_edmxPath)) { project = VSHelpers.GetProjectForDocument(_edmxPath); } // Resolve and validate the template file path var errorMessages = new DatabaseGenerationEngine.PathValidationErrorMessages { NullFile = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotSet, DisplayName), NonValid = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotValid, DisplayName), ParseError = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ExceptionParsingTemplateFilePath, DisplayName), NonFile = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNonFile, DisplayName), NotInProject = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplateFileNotInProject, DisplayName), NonExistant = String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_TemplateFileNotExists, DisplayName) }; var templateFileInfo = DatabaseGenerationEngine.ResolveAndValidatePath( project, templatePath, errorMessages); var resolvedTemplatePath = templateFileInfo.FullName; // The workflow will catch any IO exceptions and wrap them in a friendly message var templateContents = File.ReadAllText(resolvedTemplatePath); // Since we are leveraging the VS T4 Host, we will have to ask the environment how to resolve any other assemblies. // The VS T4 Host only resolves: (a) rooted paths (b) GAC'd dlls and (c) Referenced dlls in the project, if a hierarchy is provided // This is a little risky here, but we will use a strict regular expression to replace the assembly references with resolved paths templateContents = Regex.Replace( templateContents, _assemblyDirectiveRegex.ToString(), match => { Debug.Assert( match.Groups.Count == 2, "If we have a match, we should only ever have two groups, the last of which is the assembly path"); if (match.Groups.Count == 2) { var resolvedAssemblyPath = match.Groups[1].Value; // project can be null if we are running via tests. In this case, the custom macros will // be used resolvedAssemblyPath = VsUtils.ResolvePathWithMacro( project, resolvedAssemblyPath, new Dictionary <string, string> { { VsUtils.DevEnvDirMacroName, VsUtils.GetVisualStudioInstallDir() }, { ExtensibleFileManager.EFTOOLS_USER_MACRONAME, ExtensibleFileManager.UserEFToolsDir.FullName }, { ExtensibleFileManager.EFTOOLS_VS_MACRONAME, ExtensibleFileManager.VSEFToolsDir.FullName } }); return(String.Format(CultureInfo.InvariantCulture, AssemblyDirectiveFormat, resolvedAssemblyPath)); } return(match.Value); }); var textTemplatingService = Package.GetGlobalService(typeof(STextTemplating)) as ITextTemplating; Debug.Assert(textTemplatingService != null, "ITextTemplating could not be found from the IServiceProvider"); if (textTemplatingService == null) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTextTemplatingServiceNotFound, resolvedTemplatePath)); } // Process the template, keeping track of errors var templateCallback = new TemplateCallback(); var templateOutput = String.Empty; textTemplatingService.BeginErrorSession(); templateOutput = textTemplatingService.ProcessTemplate(resolvedTemplatePath, templateContents, templateCallback, null); if (textTemplatingService.EndErrorSession()) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, Resources.TemplateErrorsEncountered, resolvedTemplatePath, templateCallback.ErrorStringBuilder)); } return(templateOutput); }