Ejemplo n.º 1
0
        public EdmPackageFixture()
        {
            _modelManager = new EntityDesignModelManager(
                new EFArtifactFactory(),
                new EFArtifactSetFactory());

            _package = new MockPackage(_modelManager);
        }
        private static bool LoadAndValidateFiles(
            IEnumerable<VSFileFinder.VSFileInfo> edmxFilesToValidate, bool doEscherValidation, Func<EFArtifact, bool> shouldValidateArtifact)
        {
            var validationSuccessful = true;

            // load all the artifacts, and clear out the error list for them.
            using (var modelManager = new EntityDesignModelManager(new VSArtifactFactory(), new VSArtifactSetFactory()))
            {
                foreach (var vsFileInfo in edmxFilesToValidate)
                {
                    var uri = Utils.FileName2Uri(vsFileInfo.Path);
                    try
                    {
                        var artifact = GetArtifactForValidation(uri, vsFileInfo.Hierarchy, modelManager);
                        if (artifact != null
                            && shouldValidateArtifact(artifact))
                        {
                            // we need to continue validating even if validation for an artifact failed so just
                            // set the flag and continue validating.
                            if (!ValidateArtifactAndWriteErrors(artifact, vsFileInfo, doEscherValidation))
                            {
                                validationSuccessful = false;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // an exception occurred loading the document, so add an error for it into the error pane.
                        var errorList = ErrorListHelper.GetSingleDocErrorList(vsFileInfo.Hierarchy, vsFileInfo.ItemId);

                        Debug.Assert(errorList != null, "errorList is null!");

                        errorList.AddItem(
                            EFModelErrorTaskFactory
                                .CreateErrorTask(uri.LocalPath, e, vsFileInfo.Hierarchy, vsFileInfo.ItemId));

                        validationSuccessful = false;
                    }
                }
            }

            return validationSuccessful;
        }
        public int OnAfterRenameFiles(
            int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgszMkOldNames, string[] rgszMkNewNames,
            VSRENAMEFILEFLAGS[] rgFlags)
        {
            var hr = VSConstants.S_OK;
            var handler = AfterRenameFile;
            if (handler != null)
            {
                for (var fileCount = 0; fileCount < cFiles; fileCount++)
                {
                    var args = new ModelChangeEventArgs();
                    args.OldFileName = rgszMkOldNames[fileCount];
                    args.NewFileName = rgszMkNewNames[fileCount];
                    args.ProjectObj = GetProjectFromArray(cProjects, fileCount, rgpProjects, rgFirstIndices);
                    if (args.ProjectObj == null)
                    {
                        continue;
                    }

                    var newUri = Utils.FileName2Uri(args.NewFileName);
                    ModelManager modelManager = PackageManager.Package.ModelManager;
                    var artifact = modelManager.GetArtifact(newUri);
                    ModelManager tempModelManager = null;
                    try
                    {
                        if (artifact == null
                            && Path.GetExtension(args.NewFileName)
                                   .Equals(EntityDesignArtifact.ExtensionEdmx, StringComparison.CurrentCulture))
                        {
                            tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory());
                            artifact = tempModelManager.GetNewOrExistingArtifact(
                                newUri, new StandaloneXmlModelProvider(PackageManager.Package));
                        }
                        args.Artifact = artifact;

                        hr = handler(this, args);
                    }
                    finally
                    {
                        if (tempModelManager != null)
                        {
                            tempModelManager.Dispose();
                        }
                    }
                }
            }
            return hr;
        }
        // <summary>
        //     Loads document in an temporary model manager to see if it is designer safe.
        // </summary>
        private static bool IsUnloadedDocumentDesignerSafe(Uri uri)
        {
            Debug.Assert(uri != null, "uri is null");

            using (var tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory()))
            {
                using (var xmlModelProvider = new StandaloneXmlModelProvider(PackageManager.Package))
                {
                    var artifact = tempModelManager.GetNewOrExistingArtifact(uri, xmlModelProvider);
                    Debug.Assert(artifact != null, "failed to get the artifact to determine if it is designer-safe");
                    if (artifact == null)
                    {
                        return true;
                    }
                    artifact.DetermineIfArtifactIsDesignerSafe();
                    return artifact.IsDesignerSafe;
                }
            }
        }
Ejemplo n.º 5
0
 internal MockPackage(EntityDesignModelManager manager)
 {
     _manager = manager;
     PackageManager.Package = this;
 }
            protected override void PostInvoke(CommandProcessorContext cpc)
            {
                base.PostInvoke(cpc);

                if (_settings.HasExtensionChangedModel)
                {
                    //
                    // we validate here in the command so that we can throw to abort the transaction on errors
                    //

                    //
                    // since the xml editor transaction hasn't been committed, the model state isn't totally valid and we get
                    // a bunch of assertions if we use the model backed by the xml editor.  For example, if we try to validate, 
                    // we get assertions about being unable to find line numbers.  Because of this, we create a temporary artifact
                    // on the updated model and validate that.
                    //
                    EntityDesignModelManager tempModelManager = null;
                    EFArtifact tempArtifact = null;
                    InMemoryXmlModelProvider modelProvider = null;

                    try
                    {
                        var uri = _artifact.Uri;
                        modelProvider = new InMemoryXmlModelProvider(uri, _artifact.XDocument.ToString());
                        // NOTE:  use an EFArtifact with VSArtifactSet.  This is so we get the in-vs behavior of artifact sets, but don't rely on VS loading the model into the RDT, etc..
                        // We passed in instance of EFArtifactFactory to the model manager because we don't want the DiagramArtifact is instantiated and loaded because:
                        // - We are only interested in Model validation; there is no need to load diagram.
                        // - InMemoryXmlModelProvider will throw when we request to load diagram model since diagram model URI is different from entity model URI.
                        tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory());
                        tempArtifact = tempModelManager.GetNewOrExistingArtifact(uri, modelProvider);
                        ValidateArtifact(tempModelManager, tempArtifact, WizardKind.UpdateModel);
                    }
                    finally
                    {
                        if (tempArtifact != null)
                        {
                            tempArtifact.Dispose();
                        }
                        if (tempModelManager != null)
                        {
                            tempModelManager.Dispose();
                        }
                        if (modelProvider != null)
                        {
                            modelProvider.Dispose();
                        }
                    }
                }
            }
        private static void ValidateArtifact(EntityDesignModelManager modelManager, EFArtifact artifact, WizardKind kind)
        {
            var errorsFound = false;
            Exception caughtException = null;

            try
            {
                VsUtils.EnsureProvider(artifact);
                var artifactSet = (EntityDesignArtifactSet)modelManager.GetArtifactSet(artifact.Uri);
                modelManager.ValidateAndCompileMappings(artifactSet, false); // just run the runtime's validation
                var errors = artifactSet.GetAllErrorsForArtifact(artifact);
                if (errors != null
                    && errors.Count > 0)
                {
                    foreach (var error in errors)
                    {
                        if (error.IsError())
                        {
                            errorsFound = true;
                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                caughtException = e;
            }

            if (errorsFound || caughtException != null)
            {
                var message = string.Empty;
                if (kind == WizardKind.Generate)
                {
                    message = Resources.Extensibility_ExtensionMadeBadModel;
                }
                else if (kind == WizardKind.UpdateModel)
                {
                    message = Resources.Extensibility_ExtensionMadeBadModel_Update;
                }

                if (caughtException == null)
                {
                    throw new InvalidOperationException(message);
                }
                else
                {
                    throw new InvalidOperationException(message, caughtException);
                }
            }
        }
        private static bool ProcessAccumulatedInfo(
            EditingContext editingContext, EntityDesignArtifact existingArtifact, ModelBuilderSettings settings)
        {
            var schemaVersionChanged = existingArtifact.SchemaVersion != settings.TargetSchemaVersion;

            EntityDesignModelManager tempModelManager = null;
            FileInfo tempEdmxFile = null;
            Uri tempEdmxFileUri = null;

            try
            {
                // set up new temporary ModelManager
                // NOTE:  use an EFArtifact with VSArtifactSet.  This is so we get the in-vs behavior of artifact sets, 
                // but don't rely on VS loading the model into the RDT, etc..
                tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory());

                tempEdmxFile = ConstructTempEdmxFile(settings);
                tempEdmxFileUri = new Uri(tempEdmxFile.FullName, UriKind.Absolute);
                var tempArtifactBasedOnDatabase = tempModelManager.GetNewOrExistingArtifact(tempEdmxFileUri, new VanillaXmlModelProvider());

                // if a model generation extension has changed the model, ensure that it is 
                // valid before we start to process it
                if (settings.HasExtensionChangedModel)
                {
                    ValidateArtifact(tempModelManager, tempArtifactBasedOnDatabase, WizardKind.Generate);
                }

                // Note: later we want the diagram shapes and connectors to be created in the current active diagram
                // so set TransactionContext appropriately.
                EfiTransactionContext transactionContext = null;
                var contextItem = editingContext.Items.GetValue<DiagramManagerContextItem>();
                if (contextItem != null
                    && contextItem.DiagramManager != null)
                {
                    var activeDiagram = contextItem.DiagramManager.ActiveDiagram;
                    if (activeDiagram != null)
                    {
                        transactionContext = new EfiTransactionContext();
                        transactionContext.Add(
                            EfiTransactionOriginator.TransactionOriginatorDiagramId, new DiagramContextItem(activeDiagram.DiagramId));
                    }
                }

                // clear search if active (Note: in Model.Tests it is OK for below to be null)
                var explorerInfo = editingContext.Items.GetValue<ExplorerWindow.ExplorerInfo>();
                if (explorerInfo != null)
                {
                    var explorerFrame = explorerInfo._explorerFrame;
                    if (explorerFrame != null)
                    {
                        if (explorerFrame.SearchIsActive)
                        {
                            explorerFrame.ResetSearchCommand.Execute(null);
                        }
                    }
                }

                var cpc = new CommandProcessorContext(
                    editingContext, EfiTransactionOriginator.UpdateModelFromDatabaseId,
                    Resources.Tx_UpdateModelFromDatabase, null, transactionContext);

                if (schemaVersionChanged)
                {
                    // changing namespaces must be done in a separate transaction otherwise XmlEditor
                    // will not pick-up changes made to xml after namespaces are changed 
                    CommandProcessor.InvokeSingleCommand(
                        cpc,
                        new RetargetXmlNamespaceCommand(existingArtifact, settings.TargetSchemaVersion));
                }

                // Update the existing artifact based on tempArtifactBasedOnDatabase
                var commands = new List<Command>();
                var cmd = new UpdateModelFromDatabaseCommand(tempArtifactBasedOnDatabase);
                commands.Add(cmd);

                // set up our post event to clear out the error list
                cmd.PostInvokeEvent +=
                    (o, e) =>
                        {
                            var errorList =
                                ErrorListHelper.GetSingleDocErrorList(e.CommandProcessorContext.Artifact.Uri);
                            if (errorList != null)
                            {
                                errorList.Clear();
                            }
                        };

                DesignerInfo designerInfo;
                if (existingArtifact.DesignerInfo().TryGetDesignerInfo(OptionsDesignerInfo.ElementName, out designerInfo))
                {
                    var optionsDesignerInfo = designerInfo as OptionsDesignerInfo;
                    Debug.Assert(optionsDesignerInfo != null, "expected non-null optionsDesignerInfo");
                    if (optionsDesignerInfo != null)
                    {
                        // pluralization checkbox
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.CheckPluralizationInWizard,
                            OptionsDesignerInfo.AttributeEnablePluralization,
                            settings.UsePluralizationService, optionsDesignerInfo, commands);

                        // include FKs in model checkbox
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.CheckIncludeForeignKeysInModel,
                            OptionsDesignerInfo.AttributeIncludeForeignKeysInModel,
                            settings.IncludeForeignKeysInModel, optionsDesignerInfo, commands);

                        // ensure UseLegacyProvider is set
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.UseLegacyProvider,
                            OptionsDesignerInfo.AttributeUseLegacyProvider,
                            settings.UseLegacyProvider, optionsDesignerInfo, commands);
                    }
                }

                // create a new FunctionImport for every new Function created (whether composable or not)
                // (or delete Functions if ProgressDialog did not finish successfully)
                // Note: this must take place as a DelegateCommand as ProcessStoredProcedureReturnTypeInformation()
                // can depend on finding the existing Functions to delete. And it won't find them until the
                // ReplaceSsdlCommand within UpdateModelFromDatabaseCommand has executed.
                var createMatchingFunctionImportsDelegateCommand = new DelegateCommand(
                    () =>
                        {
                            var functionImportCommands = new List<Command>();
                            ProgressDialogHelper.ProcessStoredProcedureReturnTypeInformation(
                                existingArtifact, settings.NewFunctionSchemaProcedures, functionImportCommands, true);

                            if (functionImportCommands.Count > 0)
                            {
                                new CommandProcessor(cpc, functionImportCommands)
                                    .Invoke();
                            }
                        });
                commands.Add(createMatchingFunctionImportsDelegateCommand);

                // if needed, create a command to dispatch any extensions
                if (EscherExtensionPointManager.LoadModelGenerationExtensions().Length > 0)
                {
                    var dispatchCommand = new DispatchToExtensionsCommand(settings);
                    commands.Add(dispatchCommand);
                }

                // do all the work here in one transaction
                new CommandProcessor(cpc, commands)
                    .Invoke();

                // if an extension has changed the model, do a full reload
                if (schemaVersionChanged || settings.HasExtensionChangedModel)
                {
                    return true;
                }
                else
                {
                    // reset the is-designer safe flag - this can be set incorrectly when the document is reloaded after ssdl has been updated,
                    // but csdl & msl haven't.  Here, the model is correct, but we need to get views to refresh themselves after we
                    // reset the is-designer-safe flag.
                    // Perf note: reloading the artifact can take some time - so only reload if IsDesignerSafe has changed
                    var isDesignerSafeBefore = existingArtifact.IsDesignerSafe;
                    existingArtifact.DetermineIfArtifactIsDesignerSafe();
                    var isDesignerSafeAfter = existingArtifact.IsDesignerSafe;
                    if (isDesignerSafeAfter != isDesignerSafeBefore)
                    {
                        existingArtifact.FireArtifactReloadedEvent();
                    }
                }
            }
            finally
            {
                // remove tempArtifactBasedOnDatabase to dispose EFObject's properly
                if (tempEdmxFileUri != null
                    && tempModelManager != null)
                {
                    tempModelManager.ClearArtifact(tempEdmxFileUri);
                }

                // dispose of our temp model manager
                if (tempModelManager != null)
                {
                    tempModelManager.Dispose();
                }

                // delete temporary file
                if (tempEdmxFile != null
                    && tempEdmxFile.Exists)
                {
                    try
                    {
                        tempEdmxFile.Delete();
                    }
                    catch (IOException)
                    {
                        // do nothing if delete fails
                    }
                }
            }

            return false;
        }
        protected override byte[] GenerateCode(string inputFileName, string inputFileContent, string defaultNamespace)
        {
            byte[] generatedBytes = null;
            var generatedCode = string.Empty;

            var projectItem = SiteServiceProvider.GetService(typeof(ProjectItem)) as ProjectItem;

            // Check if this is a rename operation here. The SFG gets called during a rename on website projects
            // and attempts to rollback the code-behind file if the SFG fails, but before the rename of the
            // code-behind file. We don't want to hose the existing code-behind file so we return back the bytes
            // of the previous code-behind file.
            if (projectItem != null
                && IsAfterARename(projectItem))
            {
                var generatedCodeFile = GetCodeGenFilePathFromInputFile(inputFileName);
                if (File.Exists(generatedCodeFile))
                {
                    return GetBytesOfExistingCodeGenFile(generatedCodeFile);
                }
            }

            // init Language
            var languageOption = LanguageOption.GenerateCSharpCode;
            try
            {
                var defaultExtension = DefaultExtensionString.ToUpperInvariant();
                if (defaultExtension.Contains(".CS"))
                {
                    languageOption = LanguageOption.GenerateCSharpCode;
                }
                else if (defaultExtension.Contains(".VB"))
                {
                    languageOption = LanguageOption.GenerateVBCode;
                }
                else
                {
                    throw new NotSupportedException(Strings.UnknownLanguage);
                }
            }
            catch (Exception e)
            {
                string commentString;
                if (languageOption == LanguageOption.GenerateVBCode)
                {
                    commentString = "' " + e.Message;
                }
                else
                {
                    commentString = "// " + e.Message;
                }
                generatedBytes = Encoding.UTF8.GetBytes(commentString);
                return generatedBytes;
            }

            // ensure that our package is loaded
            try
            {
                PackageManager.LoadEDMPackage(SiteServiceProvider);
            }
            catch (Exception)
            {
                // It would be nice to add an error in the error list, but you need an IServiceProvider to do this
                // We use our package usually for this, but here, our pacakge failed to load.  Raise a message box
                VsUtils.ShowErrorDialog(Resources.LoadOurPackageError);

                string commentString;
                if (languageOption == LanguageOption.GenerateVBCode)
                {
                    commentString = "' " + Resources.LoadOurPackageError;
                }
                else
                {
                    commentString = "// " + Resources.LoadOurPackageError;
                }
                generatedBytes = Encoding.UTF8.GetBytes(commentString);
                return generatedBytes;
            }

            if (InputFileHasContent(inputFileContent))
            {
                var projectItemUri = Utils.FileName2Uri(inputFileName);

                ModelManager modelManager = PackageManager.Package.ModelManager;
                ModelManager tempModelManager = null;

                try
                {
                    // First check the ModelManager to see if the artifact was loaded by the designer or if it was persisted from an earlier code-gen attempt
                    var artifact = modelManager.GetArtifact(projectItemUri);
                    if (artifact == null)
                    {
                        tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory());
                        artifact = tempModelManager.GetNewOrExistingArtifact(
                            projectItemUri, new StandaloneXmlModelProvider(PackageManager.Package));
                        Debug.Assert(artifact != null, "We should have created the artifact from the temporary model manager");

                        // Since we created the artifact purely for code-gen, we need to mark it as such so the designer knows not to re-use this
                        // artifact later.
                        foreach (var codeGenArtifact in artifact.ArtifactSet.Artifacts)
                        {
                            codeGenArtifact.IsCodeGenArtifact = true;
                        }
                    }

                    // First check if the 'CodeGenerationStrategy' option is set to 'Default'. 
                    // If there's no or empty value, we assume 'Default'.
                    var codeGenStrategy = ModelHelper.GetDesignerPropertyValueFromArtifact(
                        OptionsDesignerInfo.ElementName, OptionsDesignerInfo.AttributeCodeGenerationStrategy, artifact);
                    if (String.IsNullOrEmpty(codeGenStrategy)
                        || codeGenStrategy.Equals(Resources.Default))
                    {
                        // navigate to the conceptual element
                        var cModel = artifact.ConceptualModel();
                        if (cModel != null)
                        {
                            IList<EdmSchemaError> generatorErrors;

                            using (var output = new StringWriter(CultureInfo.InvariantCulture))
                            {
                                // set up namespace to use for code-gen. defaultNamespace is computed by VS to account for
                                // folder path in the project, custom tool namespace, and differences between C#, VB, and web-site projects.
                                defaultNamespace = GetCodeNamespace(defaultNamespace, artifact);

                                // generate code
                                generatorErrors =
                                    new LegacyCodeGenerationDriver(languageOption, artifact.SchemaVersion)
                                        .GenerateCode(artifact, defaultNamespace, output);

                                generatedCode = output.ToString();
                            }

                            // TODO: pass on validation to our designer so that we validate the MSL and SSDL in addition to the CSDL
                            // Insert new errors into the ErrorList window
                            ProcessErrors(generatorErrors, projectItemUri, artifact);

                            if (generatorErrors.Count > 0
                                || string.IsNullOrEmpty(generatedCode))
                            {
                                // We do not want to bring the error list to the front if there are code generation errors
                                // since this could interrupt the editing of the model.
                                // in case of errors generate a comment in the code which will indicate 
                                // that the file failed to generate properly
                                generatedCode = GetCodeGenerationErrorComment(languageOption, inputFileName);
                            }

                            generatedBytes = Utils.StringToBytes(generatedCode, Encoding.UTF8);
                        }
                    }
                    else
                    {
                        generatedCode = GetCodeGenerationDisabledComment(languageOption, inputFileName);
                        generatedBytes = Utils.StringToBytes(generatedCode, Encoding.UTF8);
                    }
                }
                catch (Exception e)
                {
                    GeneratorErrorCallback(false, 0, e.Message, 0, 0);
                    ErrorList.BringToFront();
                }
                finally
                {
                    if (tempModelManager != null)
                    {
                        tempModelManager.Dispose();
                        tempModelManager = null;
                    }
                }
            }
            return generatedBytes;
        }