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));
            }
        }
示例#4
0
        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);
        }