/// <summary> /// - base calls to DiagramDocView : ModelingDocView : ModelingWindowPane /// if (this.CurrentDiagram != null) -> this.CountShapes /// else calls to ModelingWindowPane /// </summary> /// <returns></returns> protected override uint CountAllObjects() { if (IsArtifactDesignerSafe() == false && EdmUtils.ShouldShowByRefDebugHelpers() == false) { return(0); } else { // the scope of this 'all' list should be the selectable shapes in the designer // so let the base class count these var count = base.CountAllObjects(); if (count > (EntityDesignerDiagram.IMPLICIT_AUTO_LAYOUT_CEILING / 2)) { // if there are too many objects, just tell the system that we have 1 item // which will cause only the selected item to show up in the drop-down list on top // of the property window return(1); } else { return(count); } } }
private string GetUniqueModelNamespace() { using (new VsUtils.HourglassHelper()) { var existingNamespaces = InitializeExistingNamespaces(Wizard.Project); // set the storage target to the initial catalog but if we're targeting a database project // then set it to the database name which is by definition unique. var storageTarget = Wizard.ModelBuilderSettings.InitialCatalog; // set the default name for the Model Namespace string trialNamespace; if (String.IsNullOrEmpty(storageTarget)) { trialNamespace = ModelConstants.DefaultModelNamespace; } else { trialNamespace = EdmUtils.ConstructValidModelNamespace( storageTarget + ModelConstants.DefaultModelNamespace, ModelConstants.DefaultModelNamespace); } return(EdmUtils.ConstructUniqueNamespace(trialNamespace, existingNamespaces)); } // restore cursor }
// virtual for testing public virtual XmlDocument LoadConfig() { var configFilePath = GetConfigPath(); if (configFilePath != null) { // attempt to construct the config xml from the doc data if it is available try { var textLines = _vsHelpers.GetDocData(_serviceProvider, configFilePath) as IVsTextLines; return(textLines != null ? EdmUtils.SafeLoadXmlFromString( VSHelpers.GetTextFromVsTextLines(textLines), preserveWhitespace : true) : EdmUtils.SafeLoadXmlFromPath(configFilePath)); } catch (XmlException e) { VsUtils.LogStandardError( String.Format( CultureInfo.CurrentCulture, Resources.VSUtils_ExceptionParsingXml, configFilePath, e.Message), configFilePath, e.LineNumber, e.LinePosition); throw; } } return(null); }
/// <summary> /// The implementation of VsShell.ISelectionContainer.GetObjects in /// ModelingWindowPane calls either GetSelectedObjects() or GetAllObjects() /// - base calls to ModelingWindowPane /// </summary> /// <returns></returns> protected override void GetSelectedObjects(uint count, object[] objects) { // call the base class version first; objects will be populated with a // collection of DSL ModelElements base.GetSelectedObjects(count, objects); if (IsArtifactDesignerSafe() == false) { if (EdmUtils.ShouldShowByRefDebugHelpers()) { if (Context != null) { var artifact = EditingContextManager.GetArtifact(Context) as EntityDesignArtifact; if (artifact != null) { // Show at least the EFEntityModelDescriptor so we can see the by-reference property extensions // for the hydrated model var descriptor = (ObjectDescriptor)TypeDescriptor.CreateInstance(null, typeof(EFEntityModelDescriptor), null, null); descriptor.Initialize(artifact.ConceptualModel, Context, true); objects[0] = descriptor; } } } else { for (var i = 0; i < objects.Length; i++) { objects[i] = null; } } } // only show properties for single selection else { // now change this into an array of our item descriptors. var selectedModelObjects = ConvertDslModelElementArrayToItemDescriptors(objects, false); // if there are more than 1 selected object, convert the item descriptors to linked-item-descriptors. // This is so that property update can be done in 1 transaction. if (selectedModelObjects.Count > 1) { var tempSelectedModelObjects = new ArrayList(); var contextItem = new LinkedDescriptorContextItem(); foreach (var customTypeDescriptor in selectedModelObjects.ToArray().OfType <ICustomTypeDescriptor>()) { tempSelectedModelObjects.Add(new LinkedPropertyTypeDescriptor(customTypeDescriptor, contextItem)); } selectedModelObjects = tempSelectedModelObjects; } // if the lengths are not the same, then there are items (like compartments) // that are being selected, so don't change the object array if (objects.Length == selectedModelObjects.Count) { selectedModelObjects.CopyTo(objects, 0); } } }
private static ICollection <string> GetReferencesFromTemplateForProject(Project project) { ICollection <string> referenceFileNames = new List <string>(); var solution2 = project.DTE.Solution as Solution2; if (null != solution2) { // get the itemTemplate vstemplate zip file name based on the type of project and language string itemTemplateZipFile = null; var projectKind = VsUtils.GetProjectKind(project); if (projectKind == VsUtils.ProjectKind.CSharp) { itemTemplateZipFile = EntityDesigner.Utils.Constants.AdoNetEntityDataModelCSharp; } else if (projectKind == VsUtils.ProjectKind.VB) { itemTemplateZipFile = EntityDesigner.Utils.Constants.AdoNetEntityDataModelVB; } else if (projectKind == VsUtils.ProjectKind.Web) { if (VsUtils.IsWebSiteVBProject(project)) { itemTemplateZipFile = EntityDesigner.Utils.Constants.AdoNetEntityDataModelAspNetVB; } else if (VsUtils.IsWebSiteCSharpProject(project)) { itemTemplateZipFile = EntityDesigner.Utils.Constants.AdoNetEntityDataModelAspNetCSharp; } } // use the solution to get the path of the item template, look at the XML, and find all references. if (itemTemplateZipFile != null) { var itemTemplatePath = solution2.GetProjectItemTemplate(itemTemplateZipFile, project.Kind); if (!String.IsNullOrEmpty(itemTemplatePath)) { try { var xmlDocument = EdmUtils.SafeLoadXmlFromPath(itemTemplatePath); var nsmgr = new XmlNamespaceManager(xmlDocument.NameTable); nsmgr.AddNamespace("vst", "http://schemas.microsoft.com/developer/vstemplate/2005"); var referenceNodeList = xmlDocument.SelectNodes( "/vst:VSTemplate/vst:TemplateContent/vst:References/vst:Reference/vst:Assembly", nsmgr); foreach (XmlElement referenceNode in referenceNodeList) { referenceFileNames.Add(referenceNode.InnerText); } } catch { // leave it up to the build process to pick up the errors } } } } return(referenceFileNames); }
public string GetInitialModelContents(Version targetSchemaVersion) { Debug.Assert( EntityFrameworkVersion.IsValidVersion(targetSchemaVersion), "invalid schema version"); return(EdmUtils.CreateEdmxString(targetSchemaVersion, string.Empty, string.Empty, string.Empty)); }
public void GetInitialModelContents_returns_contents() { foreach (var targetSchemaVersion in EntityFrameworkVersion.GetAllVersions()) { Assert.Equal( EdmUtils.CreateEdmxString(targetSchemaVersion, string.Empty, string.Empty, string.Empty), new InitialModelContentsFactory().GetInitialModelContents(targetSchemaVersion)); } }
protected virtual ModelGenerationExtensionContext CreateContext() { Debug.Assert(VsUtils.EntityFrameworkSupportedInProject(_project, PackageManager.Package, allowMiscProject: false)); var targetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(_project, PackageManager.Package); return(new ModelGenerationExtensionContextImpl( _project, targetSchemaVersion, _currentXDocument, _fromDatabaseDocument, WizardKind)); }
protected override ModelGenerationExtensionContext CreateContext() { Debug.Assert(VsUtils.EntityFrameworkSupportedInProject(Project, PackageManager.Package, allowMiscProject: false)); var targetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(Project, PackageManager.Package); return(new UpdateModelFromDatabaseExtensionContextImpl( Project, ProjectItem, targetSchemaVersion, CurrentDocument, FromDatabaseDocument, OriginalDocument, UpdateModelDocument)); }
internal static HashSet <string> InitializeExistingNamespaces(Project project) { var existingNamespaces = new HashSet <string>(); if (project != null) { // find the namespace used in the CSDL section of each existing edmx file in the project var vsHierarchy = VsUtils.GetVsHierarchy(project, Services.ServiceProvider); var fileFinder = new VSFileFinder(EntityDesignArtifact.ExtensionEdmx); fileFinder.FindInProject(vsHierarchy); foreach (var fileInfo in fileFinder.MatchingFiles) { try { var xmlDocument = EdmUtils.SafeLoadXmlFromPath(fileInfo.Path); foreach (var schemaVersion in EntityFrameworkVersion.GetAllVersions()) { var nsMgr = SchemaManager.GetEdmxNamespaceManager(xmlDocument.NameTable, schemaVersion); foreach ( XmlElement e in xmlDocument.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/csdl:Schema", nsMgr)) { var namespaceValue = e.GetAttribute("Namespace"); if (!string.IsNullOrEmpty(namespaceValue)) { existingNamespaces.Add(namespaceValue); } } } } // swallow various exceptions that come from reading the file or parsing xml // We just skip this document in the event of an exception. catch (IOException) { } catch (UnauthorizedAccessException) { } catch (NotSupportedException) { } catch (SecurityException) { } catch (XmlException) { } } } return(existingNamespaces); }
/// <summary> /// The implementation of VsShell.ISelectionContainer.CountObjects in /// ModelingWindowPane calls either CountSelectedObjects() or CountAllObjects() /// - base calls to ModelingWindowPane /// </summary> /// <returns></returns> protected override uint CountSelectedObjects() { if (!IsArtifactDesignerSafe() && !EdmUtils.ShouldShowByRefDebugHelpers()) { return(0); } else { // we can just call the base class because the count of selected designer elements // and their corresponding ItemDescriptors should be the same return(base.CountSelectedObjects()); } }
/// <summary> /// Set properties such as "Custom Tool" and "Item Type" /// </summary> internal static void SetProjectItemProperties(ProjectItem projectItem, VisualStudioProjectSystem applicationType) { // set the CustomTool property for the SingleFileGenerator EdmUtils.ToggleEdmxItemCustomToolProperty(projectItem, true); // set the ItemType property to "EntityDeploy". This is the "build action" of the item. if (applicationType != VisualStudioProjectSystem.Website) { var prop = projectItem.Properties.Item(ModelObjectItemWizard.ItemTypePropertyName); if (prop != null) { prop.Value = ModelObjectItemWizard.EntityDeployBuildActionName; } } }
/// <summary> /// Creates a concrete implementation of ModelConversionExtensionContext, use this ctor when loading /// </summary> internal ModelConversionContextImpl( Project project, ProjectItem projectItem, FileInfo fileInfo, Version runtimeVersion, string original) { Debug.Assert(fileInfo != null, "fileInfo should not be null"); Debug.Assert(runtimeVersion != null, "runtimeVersion should not be null"); Debug.Assert(original != null, "original should not be null"); _project = project; _projectItem = projectItem; _fileInfo = fileInfo; _targetSchemaVersion = runtimeVersion; _current = XDocument.Parse(EdmUtils.CreateEdmxString(runtimeVersion, String.Empty, String.Empty, String.Empty)); _protectCurrent = false; _original = original; AddEventHandler(); }
private static void AddMissingReferencesForWebsite(VSWebSite webSiteProject, ICollection <string> referenceFileNames) { // first convert the enumerable into a hash for quick lookup var websiteReferenceHash = new HashSet <string>(); var websiteReferenceEnumerator = webSiteProject.References.GetEnumerator(); var netRefPath = EdmUtils.GetRuntimeAssemblyPath(webSiteProject.Project, Services.ServiceProvider); while (websiteReferenceEnumerator.MoveNext()) { var assemblyReference = websiteReferenceEnumerator.Current as AssemblyReference; if (assemblyReference != null) { websiteReferenceHash.Add(assemblyReference.Name); } } foreach (var referenceFileName in referenceFileNames) { if (!websiteReferenceHash.Contains(referenceFileName)) { // first try the GAC try { webSiteProject.References.AddFromGAC(referenceFileName); } catch (FileNotFoundException) { // attempt to add the file from the net framework directory. // TODO: We should check OOB DataFx Installation folder first before looking at .net framework folder. // Tracked by bug: 740496 try { webSiteProject.References.AddFromFile(Path.Combine(netRefPath, referenceFileName)); } catch (FileNotFoundException) { // can't do anything else; leave it up to the build process to pick up the // errors and encourage the user to add the references manually. } } } } }
internal static bool ValidateNamespace(TextBox modelNamespaceTextBox, ModelBuilderSettings modelBuilderSettings) { if (!EdmUtils.IsValidModelNamespace(modelNamespaceTextBox.Text)) { var s = ModelWizard.Properties.Resources.ConnectionStringNonValidIdentifier; VsUtils.ShowErrorDialog(String.Format(CultureInfo.CurrentCulture, s, modelNamespaceTextBox.Text)); modelNamespaceTextBox.Focus(); return(false); } // the Model Namespace and the Entity Container name must differ if (ModelBuilderWizardForm.ModelNamespaceAndEntityContainerNameSame(modelBuilderSettings)) { var s = ModelWizard.Properties.Resources.NamespaceAndEntityContainerSame; VsUtils.ShowErrorDialog(String.Format(CultureInfo.CurrentCulture, s, modelBuilderSettings.AppConfigConnectionPropertyName)); modelNamespaceTextBox.Focus(); return(false); } return(true); }
int IVsEditorFactoryNotify.NotifyItemAdded(uint grfEFN, IVsHierarchy pHier, uint itemid, string pszMkDocument) { object o; var hr = pHier.GetProperty(itemid, (int)__VSHPROPID.VSHPROPID_ExtObject, out o); if (NativeMethods.Succeeded(hr)) { var projectItem = o as ProjectItem; if (projectItem != null && VsUtils.EntityFrameworkSupportedInProject(projectItem.ContainingProject, ServiceProvider, allowMiscProject: false)) { if (EdmUtils.IsDataServicesEdmx(projectItem.get_FileNames(1))) { // if the EDMX has a data services node, don't add the SingleFileGenerator, etc. return(VSConstants.S_OK); } IOleServiceProvider oleSP; pHier.GetSite(out oleSP); using (var sp = new ServiceProvider(oleSP)) { var appType = VsUtils.GetApplicationType(sp, projectItem.ContainingProject); // set the project item properties SetProjectItemProperties(projectItem, appType); } if (grfEFN != (uint)__EFNFLAGS.EFN_ClonedFromTemplate) { // we're not adding from template i.e. Add Existing Item var referenceFileNames = GetReferencesFromTemplateForProject(projectItem.ContainingProject); AddMissingReferences(projectItem, referenceFileNames); AddBuildProvider(projectItem); } } } return(VSConstants.S_OK); }
internal static bool ShowWarningDialogAndSaveDismissOption( string formattedTitle, string formattedMessage, string regKeyName, ButtonMode buttonMode) { var cancelled = true; var service = Services.ServiceProvider.GetService(typeof(IUIService)) as IUIService; Debug.Assert(service != null, "service should not be null"); if (service != null) { using (var dialog = new DismissableWarningDialog(formattedTitle, formattedMessage, buttonMode)) { if (service.ShowDialog(dialog) == DialogResult.OK) { cancelled = false; var showAgain = dialog.chkWarning.Checked == false; EdmUtils.SaveUserSetting(regKeyName, showAgain.ToString()); } } } return(cancelled); }
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 static void EditFunctionImport( EditingContext editingContext, FunctionImport functionImport, StorageEntityModel sModel, ConceptualEntityModel cModel, ConceptualEntityContainer cContainer, object selectedObject, string originatingId) { Debug.Assert(editingContext != null, "editingContext should not be null"); Debug.Assert(!string.IsNullOrEmpty(originatingId), "originatingId should not be null or empty"); // show dialog appropriate to framework version var result = ShowNewFunctionImportDialog( functionImport.Function, functionImport.LocalName.Value, sModel, cModel, cContainer, DialogsResource.NewFunctionImportDialog_EditFunctionImportTitle, selectedObject); // if user selected OK on the dialog then create the FunctionImport if (DialogResult.OK == result.DialogResult) { var commands = new List <Command>(); var cp = new CommandProcessor(editingContext, originatingId, Resources.Tx_UpdateFunctionImport); CreateComplexTypeCommand createComplexTypeCommand = null; // Make the decision based on what is returned by the dialog. // If return type is a string and result schema is not null, that means the user would like to create a new complex type for the function import return. if (result.ReturnType is string && result.Schema != null) { createComplexTypeCommand = CreateMatchingFunctionImportCommand.AddCreateComplexTypeCommands( sModel, result.ReturnType as string, result.Schema.RawColumns, commands); } // If ReturnType is a complex type and result schema is not null, the complex type needs to be updated to be in sync with schema columns. else if (result.ReturnType is ComplexType && result.Schema != null) { var complexType = result.ReturnType as ComplexType; // Create Column properties dictionary. The keys will be either property's type-mapping column name if availabe or property's name. var propertiesDictionary = complexType.Properties().ToDictionary(p => EdmUtils.GetFunctionImportResultColumnName(functionImport, p)); CreateMatchingFunctionImportCommand.AddChangeComplexTypePropertiesCommands( complexType, propertiesDictionary, result.Schema.RawColumns, commands); } // construct Dictionary mapping property name to column name for FunctionImportMapping IDictionary <string, string> mapPropertyNameToColumnName = null; if (result.Schema != null) { mapPropertyNameToColumnName = ModelHelper.ConstructComplexTypePropertyNameToColumnNameMapping(result.Schema.Columns.Select(c => c.Name).ToList()); } // change the FunctionImport and FunctionImportMapping to match ChangeFunctionImportCommand cmdFuncImpSproc = null; // if result.IsComposable is true then set to True, but if false then use None if existing value is None, otherwise False var resultIsComposable = (result.IsComposable ? BoolOrNone.TrueValue : (BoolOrNone.NoneValue == functionImport.IsComposable.Value ? BoolOrNone.NoneValue : BoolOrNone.FalseValue)); if (createComplexTypeCommand == null) { cmdFuncImpSproc = new ChangeFunctionImportCommand( cContainer, functionImport, result.Function, result.FunctionName, resultIsComposable, true, result.ReturnType); // Create explicit function-import result type mapping if the return type is a complex type. if (result.ReturnType is ComplexType) { cmdFuncImpSproc.PostInvokeEvent += (o, eventArgs) => { if (functionImport != null && functionImport.FunctionImportMapping != null) { // CreateFunctionImportTypeMappingCommand will be no op function-import's return is unchanged. CommandProcessor.InvokeSingleCommand( cp.CommandProcessorContext , new CreateFunctionImportTypeMappingCommand( functionImport.FunctionImportMapping, result.ReturnType as ComplexType) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } }; } } else { // Pass in the pre-req command to create complex type to the command. cmdFuncImpSproc = new ChangeFunctionImportCommand( cContainer, functionImport, result.Function, result.FunctionName, resultIsComposable, createComplexTypeCommand); // Create explicit function-import result type mapping if the return type is a complex type. cmdFuncImpSproc.PostInvokeEvent += (o, eventArgs) => { if (functionImport != null && functionImport.FunctionImportMapping != null) { CommandProcessor.InvokeSingleCommand( cp.CommandProcessorContext, new CreateFunctionImportTypeMappingCommand( functionImport.FunctionImportMapping, createComplexTypeCommand) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } }; } commands.Add(cmdFuncImpSproc); commands.ForEach(x => cp.EnqueueCommand(x)); cp.Invoke(); } }
/// <summary> /// This API supports the Entity Framework infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="automationObject"> This API supports the Entity Framework infrastructure and is not intended to be used directly from your code. </param> /// <param name="replacementsDictionary"> This API supports the Entity Framework infrastructure and is not intended to be used directly from your code. </param> /// <param name="runKind"> This API supports the Entity Framework infrastructure and is not intended to be used directly from your code. </param> /// <param name="customParams"> This API supports the Entity Framework infrastructure and is not intended to be used directly from your code. </param> public void RunStarted( object automationObject, Dictionary <string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { Project project = null; var dte = automationObject as DTE2; if (EdmxUri == null) { // Wizard not launched from Escher Designer project = VsUtils.GetActiveProject(dte); Debug.Assert(project != null, "Unable to retrieve ActiveSolutionProject from DTE"); } else { // Try to get ProjectItem & project var projectItem = VsUtils.GetProjectItemForDocument(EdmxUri.LocalPath, Services.ServiceProvider); Debug.Assert(projectItem != null, "Unable to find project item for document"); if (projectItem != null) { // get the project that the input file is running in. project = projectItem.ContainingProject; // turn off code generation on the EDMX file var editingContextMgr = PackageManager.Package.DocumentFrameMgr.EditingContextManager; Debug.Assert( editingContextMgr.DoesContextExist(EdmxUri), "If the AddArtifactGeneratorWizard was launched from Escher, there should be an existing editing context"); if (editingContextMgr.DoesContextExist(EdmxUri)) { var cpc = new CommandProcessorContext( editingContextMgr.GetNewOrExistingContext(EdmxUri), EfiTransactionOriginator.AddNewArtifactGenerationItemId, Resources.Tx_SetCodeGenerationStrategy); var cmd = EdmUtils.SetCodeGenStrategyToNoneCommand(cpc.Artifact); if (cmd != null) { CommandProcessor.InvokeSingleCommand(cpc, cmd); } } } else { // Couldn't get projectItem for some reason, so default to the active project project = VsUtils.GetActiveProject(dte); } // Wizard is launched from Escher Designer. Name of the file in the designer is in the static EdmxUri property. var artifactProjectItem = VsUtils.GetProjectItemForDocument(EdmxUri.LocalPath, Services.ServiceProvider); var edmxFilePathInTemplate = String.Empty; if (VsUtils.IsLinkProjectItem(artifactProjectItem)) { // In order to determine the filename that will be placed in the .tt file, we need to first determine the // relative path of the *project item* to the root of the project, since the .tt file will be added as a sibling // of the EDMX file and the project item itself is referencing a linked file. The scenario in mind is: // ProjectRoot // '- FooFolder // '- Model.edmx (linked outside the project) // '- Model.tt <-- we want the .tt file here and the path in the template is relative to this location. var parentItem = artifactProjectItem.Collection.Parent as ProjectItem; var relativeProjectItemParentDir = String.Empty; while (parentItem != null) { relativeProjectItemParentDir = Path.Combine(parentItem.Name, relativeProjectItemParentDir); parentItem = parentItem.Collection.Parent as ProjectItem; } var projectDirectory = VsUtils.GetProjectRoot(project, Services.ServiceProvider); if (projectDirectory != null) { var absoluteProjectItemParentDir = Path.Combine(projectDirectory.FullName, relativeProjectItemParentDir); // Now we determine the relative path between the folder in the project that contains the ProjectItem and the actual path // of the artifact. var artifactParentDirInfo = new DirectoryInfo(Path.GetDirectoryName(EdmxUri.LocalPath)); var absoluteProjectItemParentDirInfo = new DirectoryInfo(absoluteProjectItemParentDir); var relativeDirPath = EdmUtils.GetRelativePath(artifactParentDirInfo, absoluteProjectItemParentDirInfo); var fileName = Path.GetFileName(EdmxUri.LocalPath); edmxFilePathInTemplate = Path.Combine(relativeDirPath, fileName); } } else { var fi = new FileInfo(EdmxUri.LocalPath); edmxFilePathInTemplate = fi.Name; } Debug.Assert(!String.IsNullOrEmpty(edmxFilePathInTemplate), "edmxFilePathInTemplate was found to be null or empty"); replacementsDictionary.Add("$edmxInputFile$", edmxFilePathInTemplate); } }
/// <summary> /// Invoked by the VS Wizard framework when this page is entered. /// Starts a background thread to retrieve table information to display /// </summary> public override void OnActivated() { base.OnActivated(); _ssdlAggregator = new DatabaseConnectionSsdlAggregator(Wizard.ModelBuilderSettings); using (new VsUtils.HourglassHelper()) { if (!_modelNamespaceInitialized) { var existingNamespaces = InitializeExistingNamespaces(Wizard.Project); // set the storage target to the initial catalog but if we're targeting a database project // then set it to the database name which is by definition unique. var storageTarget = Wizard.ModelBuilderSettings.InitialCatalog; // set the default name for the Model Namespace string trialNamespace; if (String.IsNullOrEmpty(storageTarget)) { trialNamespace = ModelConstants.DefaultModelNamespace; } else { trialNamespace = EdmUtils.ConstructValidModelNamespace( storageTarget + ModelConstants.DefaultModelNamespace, ModelConstants.DefaultModelNamespace); } modelNamespaceTextBox.Text = EdmUtils.ConstructUniqueNamespace(trialNamespace, existingNamespaces); } } // restore cursor Debug.Assert( Wizard.ModelBuilderSettings.DesignTimeConnectionString != null, "Unexpected null value for connection string"); if (Wizard.ModelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase && (!Wizard.ModelBuilderSettings.DesignTimeConnectionString.Equals(_initializedDataConnection) || Wizard.ModelBuilderSettings.UseLegacyProvider != _initializedUsingLegacyProvider)) { // Enable the treeView / labels and hide the database project label and textbox. databaseObjectTreeView.Visible = true; labelPrompt.Visible = true; // Disable wizard navigation temporarily until the background thread completes Wizard.EnableButton(ButtonType.Previous, false); Wizard.EnableButton(ButtonType.Next, false); Wizard.EnableButton(ButtonType.Finish, false); // disable model namespace textbox modelNamespaceTextBox.Enabled = false; // Clear existing database objects Wizard.ModelBuilderSettings.DatabaseObjectFilters = null; databaseObjectTreeView.TreeViewControl.Nodes.Clear(); // Put up a status message databaseObjectTreeView.ShowStatus(ModelWizard.Properties.Resources.SelectTablesPage_StatusRetrievingTablesText); // Get table names in a background thread _stopwatch.Reset(); _stopwatch.Start(); _bgWorkerPopulateTree.RunWorkerAsync(this); } }
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { var baseProperties = base.GetProperties(attributes); // clear out dictionary, as we will rebuild it in this method _propertyDescriptorToOwner.Clear(); if (RunningInVS) { // we only dispatch to extensions when we are running in VS. This is because there is a dep on vS things like ProjectItem var el = WrappedItem as EFElement; Debug.Assert(el != null, "wrapped item is null"); if (el != null) { var currentSelectionOrNull = EscherExtensionPointManager.DetermineEntityDesignerSelection(el); if (currentSelectionOrNull != null) { var currentSelection = (EntityDesignerSelection)currentSelectionOrNull; Debug.Assert((int)currentSelection != 0, "unexpected value for current selection"); var extensions = EscherExtensionPointManager.LoadPropertyDescriptorExtensions(); if (extensions.Length > 0) { // Note that if the user adds an EDMX file to their project and chooses not to save the project file, // the project item below can be null; it won't even exist in the miscellaneous files project. var projectItem = VsUtils.GetProjectItemForDocument(el.Artifact.Uri.LocalPath, PackageManager.Package); if (projectItem != null && VsUtils.EntityFrameworkSupportedInProject( projectItem.ContainingProject, PackageManager.Package, allowMiscProject: false)) { var targetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(projectItem.ContainingProject, PackageManager.Package); // Use MEF extensions to create "owner" objects that define new property descriptors to add into the property sheet. // TODO: We track 'visited factories' since have to load the App-DB contracts as well as the standard contracts, but // MEF also loads the standard contracts in addition to the App-DB contracts. Need to see if MEF can support // otherwise. var propDescriptorOwners = new List <Object>(); var visitedFactories = new HashSet <IEntityDesignerExtendedProperty>(); foreach (var ex in extensions) { if (((int)ex.Metadata.EntityDesignerSelection & (int)currentSelection) == (int)currentSelection) { // Continue processing this extension var factory = ex.Value; if (factory != null && !visitedFactories.Contains(factory)) { visitedFactories.Add(factory); try { var extensionContext = new PropertyExtensionContextImpl( EditingContext, projectItem, targetSchemaVersion, factory.GetType().Assembly.GetName().GetPublicKeyToken()); var xelem = el.XElement; var sem = el as StorageEntityModel; if (currentSelection == EntityDesignerSelection.StorageModelEntityContainer && sem != null) { xelem = sem.FirstEntityContainer.XElement; } var o = factory.CreateProperty(xelem, extensionContext); if (o != null) { propDescriptorOwners.Add(o); } } catch (Exception e) { var exceptionMessage = VsUtils.ConstructInnerExceptionErrorMessage(e); var errorMessage = String.Format( CultureInfo.CurrentCulture, Resources.Extensibility_ErrorOccurredDuringCallToExtension, factory.GetType().FullName, exceptionMessage); VsUtils.ShowErrorDialog(errorMessage); } } } } // // Create PropertyDescriptors over the new "owner" // foreach (var o in propDescriptorOwners) { var props = TypeDescriptor.GetProperties(o, attributes, false); foreach (PropertyDescriptor pd in props) { var reflectedPropertyDescriptor = new ReflectedPropertyDescriptor(EditingContext, pd, o); if (reflectedPropertyDescriptor.IsBrowsable) { if (_propertyDescriptorToOwner.ContainsKey(reflectedPropertyDescriptor)) { // handle degenerate error case where dictionary already contains key. This shouldn't happen, but this is here just to be safe. Debug.Fail("_propertyDescriptor2Owner table already contains entry"); _propertyDescriptorToOwner.Remove(reflectedPropertyDescriptor); } _propertyDescriptorToOwner.Add(reflectedPropertyDescriptor, o); baseProperties.Add(reflectedPropertyDescriptor); } } } } } } } } return(baseProperties); }
public void RunStarted( object automationObject, Dictionary <string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { // the dte is the handle into the VS environment var dte = (DTE2)automationObject; var serviceProvider = new ServiceProvider((IOleServiceProvider)dte); // get the current project that the wizard is running in var project = VsUtils.GetActiveProject(dte); Debug.Assert(project != null, "Unable to retrieve ActiveSolutionProject from DTE"); EnsureCanStartWizard(project, serviceProvider); // get file name the user chose string modelName; replacementsDictionary.TryGetValue("$rootname$", out modelName); Debug.Assert(modelName != null, "Unable to get $rootname$ from replacementsDictionary"); modelName = SanitizeModelName(modelName); PopluateReplacementDictionary(project, replacementsDictionary, modelName); _modelBuilderSettings = new ModelBuilderSettings { VSApplicationType = VsUtils.GetApplicationType(serviceProvider, project), WizardKind = WizardKind.Generate, TargetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(project, serviceProvider, useLatestIfNoEF: false), NewItemFolder = GetFolderNameForNewItems(dte, project), Project = project, ModelName = modelName, VsTemplatePath = customParams[0] as string, ReplacementDictionary = replacementsDictionary }; var form = new ModelBuilderWizardForm( serviceProvider, _modelBuilderSettings, ModelBuilderWizardForm.WizardMode.PerformAllFunctionality) { FileAlreadyExistsError = false }; try { form.Start(); } catch (Exception ex) { VsUtils.ShowErrorDialog( string.Format( CultureInfo.CurrentCulture, Resources.ModelObjectItemWizard_UnexpectedExceptionHasOccurred, ex.Message)); ClearErrors(); throw new WizardCancelledException(); } // the form.FileAlreadyExistsError flag is set in the WizardPageStart. We do it because if we // threw this exception directly from the WizardPageStart it would be swallowed and the // "Add New Item" dialog would not show up. Throwing the exception from here will make // the "Add New Item" dialog re-appear which allows the user to enter a different model name. if (form.FileAlreadyExistsError) { Marshal.ThrowExceptionForHR(VSConstants.E_ABORT); } // if they cancelled or they didn't cancel, and we didn't log that Finish was pressed, // they must have hit the X or an exception happened so cancel if (form.WizardCancelled || !form.WizardFinished) { ClearErrors(); throw new WizardCancelledException(); } Debug.Assert(ReferenceEquals(_modelBuilderSettings, form.ModelBuilderSettings)); }
internal string DispatchSaveToExtensions( IServiceProvider serviceProvider, ProjectItem projectItem, string fileContents, Lazy <IModelConversionExtension, IEntityDesignerConversionData>[] converters, Lazy <IModelTransformExtension>[] serializers) { Debug.Assert(projectItem != null, "projectItem != null"); Debug.Assert(fileContents != null, "bufferText != null"); Debug.Assert(serializers != null && converters != null, "extensions must not be null"); Debug.Assert(serializers.Any() || converters.Any(), "at least one extension expected"); ModelTransformContextImpl transformContext = null; ModelConversionContextImpl conversionContext = null; try { var original = XDocument.Parse(fileContents, LoadOptions.PreserveWhitespace); var targetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(projectItem.ContainingProject, serviceProvider); Debug.Assert(targetSchemaVersion != null, "we should not get here for Misc projects"); transformContext = new ModelTransformContextImpl(projectItem, targetSchemaVersion, original); // call the extensions that can save EDMX files first (even if we aren't going to end up in an EDMX file, let them process) VSArtifact.DispatchToSerializationExtensions(serializers, transformContext, loading: false); // get the extension of the file being loaded (might not be EDMX); this API will include the preceeding "." var fileInfo = new FileInfo(FileName); var fileExtension = fileInfo.Extension; // now if this is not an EDMX file, hand off to the extension who can convert it to the writable content if (!string.Equals(fileExtension, EntityDesignArtifact.ExtensionEdmx, StringComparison.OrdinalIgnoreCase)) { // the current document coming from the serializers becomes our original conversionContext = new ModelConversionContextImpl( projectItem.ContainingProject, projectItem, fileInfo, targetSchemaVersion, transformContext.CurrentDocument); // we aren't loading an EDMX file, so call the extensions who can process this file extension // when this finishes, then output should be a valid EDMX document VSArtifact.DispatchToConversionExtensions(converters, fileExtension, conversionContext, false); // we are done saving, so get bufferText from the OriginalDocument // TODO use Utf8StringWriter here somehow? return(conversionContext.OriginalDocument); } else { // we are saving an EDMX file, so get bufferText from the XDocument using (var writer = new Utf8StringWriter()) { transformContext.CurrentDocument.Save(writer, SaveOptions.None); return(writer.ToString()); } } } catch (XmlException) { // Don't do anything here. We will want to gracefully step out of the extension loading // and let the core designer handle this. return(fileContents); } finally { var errorList = ErrorListHelper.GetExtensionErrorList(serviceProvider); errorList.Clear(); // log any errors if (conversionContext != null) { if (conversionContext.Errors.Count > 0) { ErrorListHelper.LogExtensionErrors(conversionContext.Errors, projectItem); } conversionContext.Dispose(); } if (transformContext != null) { if (transformContext.Errors.Count > 0) { ErrorListHelper.LogExtensionErrors(transformContext.Errors, projectItem); } transformContext.Dispose(); } } }
internal override bool IsXmlValid() { // If there is a VSXmlModelProvider, we should be able to find a docdata for it. // In any other case, it doesn't matter whether there is document data or not. var docData = VSHelpers.GetDocData(PackageManager.Package, Uri.LocalPath); Debug.Assert( !(XmlModelProvider is VSXmlModelProvider) || docData != null, "Using a VSXmlModelProvider but docData is null for Artifact!"); try { XmlDocument xmldoc; if (docData != null) { var textLines = VSHelpers.GetVsTextLinesFromDocData(docData); Debug.Assert(textLines != null, "Failed to get IVSTextLines from docdata"); xmldoc = EdmUtils.SafeLoadXmlFromString(VSHelpers.GetTextFromVsTextLines(textLines)); } else { // If there is no docdata then attempt to create the XmlDocument from the internal // XLinq tree in the artifact xmldoc = new XmlDocument(); xmldoc.Load(XDocument.CreateReader()); } // For the most part, the Edmx schema version of an artifact should be in sync with the schema version // that is compatible with the project's target framework; except when the user adds an existing edmx to a project (the version could be different). // For all cases, we always want to validate using the XSD's version that matches the artifact's version. var documentSchemaVersion = base.SchemaVersion; Debug.Assert( EntityFrameworkVersion.IsValidVersion(documentSchemaVersion), "The EF Schema Version is not valid. Value:" + (documentSchemaVersion != null ? documentSchemaVersion.ToString() : "null")); // does the XML parse? If not, the load call below will throw if (EntityFrameworkVersion.IsValidVersion(documentSchemaVersion)) { var nsMgr = SchemaManager.GetEdmxNamespaceManager(xmldoc.NameTable, documentSchemaVersion); // Do XSD validation on the document. xmldoc.Schemas = EscherAttributeContentValidator.GetInstance(documentSchemaVersion).EdmxSchemaSet; var svec = new SchemaValidationErrorCollector(); // remove runtime specific lines // find the ConceptualModel Schema node RemoveRunTimeNode(xmldoc, "/edmx:Edmx/edmx:Configurations", nsMgr); RemoveRunTimeNode(xmldoc, "/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels", nsMgr); RemoveRunTimeNode(xmldoc, "/edmx:Edmx/edmx:Runtime/edmx:StorageModels", nsMgr); RemoveRunTimeNode(xmldoc, "/edmx:Edmx/edmx:Runtime/edmx:Mappings", nsMgr); xmldoc.Validate(svec.ValidationCallBack); return(svec.ErrorCount == 0); } } catch { } return(false); }
public void RunFinished() { if (_edmxItem == null) { if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.EmptyModelCodeFirst || _modelBuilderSettings.GenerationOption == ModelGenerationOption.CodeFirstFromDatabase) { Debug.Assert( _modelBuilderSettings.ModelBuilderEngine == null ^ _modelBuilderSettings.GenerationOption == ModelGenerationOption.CodeFirstFromDatabase, "Model should be null for Empty Model and not null CodeFirst from database"); AddCodeFirstItems(); } return; } var fileExtension = Path.GetExtension(_edmxItem.FileNames[1]); Debug.Assert( _modelBuilderSettings.Project.Equals(_edmxItem.ContainingProject), "ActiveSolutionProject is not the EDMX file's containing project"); using (new VsUtils.HourglassHelper()) { var package = PackageManager.Package; Window window = null; try { ConfigFileHelper.UpdateConfig(_modelBuilderSettings); // save the model generated in the wizard UI. if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase) { var writingModelWatch = new Stopwatch(); writingModelWatch.Start(); var modelEdmx = ((EdmxModelBuilderEngine)_modelBuilderSettings.ModelBuilderEngine).Edmx; if (!string.Equals(fileExtension, EntityDesignArtifact.ExtensionEdmx, StringComparison.OrdinalIgnoreCase)) { // convert the file if this isn't EDMX var edmxFileInfo = new FileInfo(_edmxItem.FileNames[1]); var conversionContext = new ModelConversionContextImpl( _edmxItem.ContainingProject, _edmxItem, edmxFileInfo, _modelBuilderSettings.TargetSchemaVersion, modelEdmx); VSArtifact.DispatchToConversionExtensions( EscherExtensionPointManager.LoadModelConversionExtensions(), fileExtension, conversionContext, loading: false); File.WriteAllText(edmxFileInfo.FullName, conversionContext.OriginalDocument); } else { // we need to use XmlWriter to output so that XmlDeclaration is preserved. using (var modelWriter = XmlWriter.Create( _edmxItem.FileNames[1], new XmlWriterSettings { Indent = true })) { modelEdmx.WriteTo(modelWriter); } } writingModelWatch.Stop(); VsUtils.LogOutputWindowPaneMessage( _edmxItem.ContainingProject, string.Format( CultureInfo.CurrentCulture, Properties.Resources.WritingModelTimeMsg, writingModelWatch.Elapsed)); } // set the ItemType for the generated .edmx file if (_modelBuilderSettings.VSApplicationType != VisualStudioProjectSystem.Website && string.Equals( fileExtension, EntityDesignArtifact.ExtensionEdmx, StringComparison.OrdinalIgnoreCase)) { _edmxItem.Properties.Item(ItemTypePropertyName).Value = EntityDeployBuildActionName; } // now open created file in VS using default viewer window = _edmxItem.Open(Constants.vsViewKindPrimary); Debug.Assert(window != null, "Unable to get window for created edmx file"); } finally { package.ModelGenErrorCache.RemoveErrors(_edmxItem.FileNames[1]); } // Construct an editing context and make all final edits that require the file is opened. var edmxFileUri = new Uri(_edmxItem.FileNames[1]); var designArtifact = package.ModelManager.GetNewOrExistingArtifact( edmxFileUri, new VSXmlModelProvider(package, package)) as EntityDesignArtifact; Debug.Assert( designArtifact != null, "artifact should be of type EntityDesignArtifact but received type " + designArtifact.GetType().FullName); Debug.Assert( designArtifact.StorageModel != null, "designArtifact StorageModel cannot be null for Uri " + edmxFileUri.AbsolutePath); Debug.Assert( designArtifact.ConceptualModel != null, "designArtifact ConceptualModel cannot be null for Uri " + edmxFileUri.AbsolutePath); if (designArtifact != null && designArtifact.StorageModel != null && designArtifact.ConceptualModel != null) { var designerSafeBeforeAddingTemplates = designArtifact.IsDesignerSafe; var editingContext = package.DocumentFrameMgr.EditingContextManager.GetNewOrExistingContext(designArtifact.Uri); Debug.Assert(editingContext != null, "Null EditingContext for artifact " + edmxFileUri.AbsolutePath); if (editingContext != null) { // Add DbContext templates when generation is GenerateFromDatabase. (connection is configured) if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase) { new DbContextCodeGenerator().AddDbContextTemplates( _edmxItem, _modelBuilderSettings.UseLegacyProvider); } // Create FunctionImports for every new Function var cp = PrepareCommandsAndIntegrityChecks(_modelBuilderSettings, editingContext, designArtifact); if (DbContextCodeGenerator.TemplateSupported(_edmxItem.ContainingProject, package)) { // Add command setting CodeGenerationStrategy to "None" for EmptyModel. (connection is not yet configured) // NOTE: For EmptyModel, the templates will be added after the connection is configured. // (i.e. during "Generate Database from Model" or "Refresh from Database") if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.EmptyModel) { var cmd = EdmUtils.SetCodeGenStrategyToNoneCommand(designArtifact); if (cmd != null) { if (cp == null) { var cpc = new CommandProcessorContext( editingContext, EfiTransactionOriginator.CreateNewModelId, Resources.Tx_SetCodeGenerationStrategy); cp = new CommandProcessor(cpc, cmd); } else { cp.EnqueueCommand(cmd); } } } } else { // Templates not supported, add reference to SDE. (.NET Framework 3.5) VsUtils.AddProjectReference(_edmxItem.ContainingProject, "System.Data.Entity"); } if (cp != null) { cp.Invoke(); } // save the artifact to make it look as though updates were part of creation _edmxItem.Save(); if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase && !designerSafeBeforeAddingTemplates) { // If the artifact became safe after adding references we need to reload it (this can happen // on .NET Framework 4 where we would originally create a v3 edmx if the user selected EF6 - // the artifact will be flagged as invalid since there is no runtime which could handle v3 // but after we added references to EF6 the artifacts becomes valid and need to be reloaded). designArtifact.DetermineIfArtifactIsDesignerSafe(); if (designArtifact.IsDesignerSafe) { Debug.Assert(!designArtifact.IsDirty, "Reloading dirty artifact - changes will be lost."); // Since the artifact was originally not valid we did not create the diagram for it. // Using ReloadDocData will cause the diagram to be recreated. Note we don't need to // reload the artifact itself since it has not changed. ((DocData) VSHelpers.GetDocData(package, designArtifact.Uri.LocalPath)).ReloadDocData(0); } } } if (window != null) { window.Activate(); } } } }
internal static bool TryGetBufferViaExtensions( IServiceProvider serviceProvider, ProjectItem projectItem, string fileContents, Lazy <IModelConversionExtension, IEntityDesignerConversionData>[] converters, Lazy <IModelTransformExtension>[] serializers, out string documentViaExtensions, out List <ExtensionError> errors) { Debug.Assert(serviceProvider != null, "serviceProvider != null"); Debug.Assert(projectItem != null, "projectItem != null"); Debug.Assert(VsUtils.EntityFrameworkSupportedInProject(projectItem.ContainingProject, serviceProvider, false)); Debug.Assert(serializers != null && converters != null, "extensions must not be null"); Debug.Assert(serializers.Any() || converters.Any(), "at least one extension expected"); errors = new List <ExtensionError>(); documentViaExtensions = ""; ModelConversionContextImpl conversionContext = null; ModelTransformContextImpl transformContext = null; try { var targetSchemaVersion = EdmUtils.GetEntityFrameworkVersion(projectItem.ContainingProject, serviceProvider); Debug.Assert(targetSchemaVersion != null, "should not get here for a Misc project"); // get the extension of the file being loaded (might not be EDMX); this API will include the preceding "." var filePath = projectItem.get_FileNames(1); var fileExtension = Path.GetExtension(filePath); XDocument originalDocument = null; // see if we are loading an EDMX file or not, and if we have any converters if (!string.Equals( fileExtension, EntityDesignArtifact.ExtensionEdmx, StringComparison.OrdinalIgnoreCase)) { conversionContext = new ModelConversionContextImpl( projectItem.ContainingProject, projectItem, new FileInfo(filePath), targetSchemaVersion, fileContents); // we aren't loading an EDMX file, so call the extensions who can process this file extension // when this finishes, then output should be a valid EDMX document VSArtifact.DispatchToConversionExtensions(converters, fileExtension, conversionContext, true); // we are done with the non-EDMX extensions so CurrentDocument will be a valid EDMX document // create the serialization context for further extensions to act on transformContext = new ModelTransformContextImpl( projectItem, targetSchemaVersion, conversionContext.CurrentDocument); } else { // we are loading an EDMX file, we can parse file contents into an XDocument try { originalDocument = XDocument.Parse(fileContents, LoadOptions.PreserveWhitespace); transformContext = new ModelTransformContextImpl( projectItem, targetSchemaVersion, originalDocument); } catch (XmlException) { // If there's an error here, don't do anything. We will want to gracefully step out of the extension loading // since the designer itself won't load. } } if (transformContext != null && originalDocument != null) { // now dispatch to those that want to work on EDMX files VSArtifact.DispatchToSerializationExtensions(serializers, transformContext, true); // TODO: this does not seem to be correct if severity is Message or Warning if (transformContext.Errors.Count == 0) { // see if any extension changed things. Note that we need to compare the serialization of // the XDocuments together since the original buffer may have different whitespace after creating the XDocument. // TODO: Why not use XNode.DeepEquals()? string newBufferContents; using (var currentDocWriter = new Utf8StringWriter()) { transformContext.CurrentDocument.Save(currentDocWriter, SaveOptions.None); newBufferContents = currentDocWriter.ToString(); } string originalBufferContents; using (var originalDocWriter = new Utf8StringWriter()) { originalDocument.Save(originalDocWriter, SaveOptions.None); originalBufferContents = originalDocWriter.ToString(); } if (!string.Equals(originalBufferContents, newBufferContents, StringComparison.Ordinal)) { documentViaExtensions = newBufferContents; return(true); } } else { errors.AddRange(transformContext.Errors); return(false); } } } finally { var errorList = ErrorListHelper.GetExtensionErrorList(serviceProvider); errorList.Clear(); // log any errors if (conversionContext != null && conversionContext.Errors.Count > 0) { ErrorListHelper.LogExtensionErrors(conversionContext.Errors, projectItem); } if (transformContext != null && transformContext.Errors.Count > 0) { ErrorListHelper.LogExtensionErrors(transformContext.Errors, projectItem); } } return(false); }