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();
                }
            }
        }
Esempio n. 2
0
        public static Attribute GetAttribute(this AttributeSyntax attribute, Type attributeType)
        {
            var ctorDirectArguments = attribute.ArgumentList
                                      .Arguments
                                      .TakeWhile(a => a.NameEquals == null && a.NameColon == null)
                                      .Select(a => a.EvaluateExpression())
                                      .ToList();

            var ctorColonArguments = attribute.ArgumentList
                                     .Arguments
                                     .SkipWhile(a => a.NameEquals == null && a.NameColon == null)
                                     .TakeWhile(a => a.NameEquals == null && a.NameColon != null)
                                     .Select(a => a.EvaluateExpression())
                                     .ToList();

            if (ctorDirectArguments.Any(a => a == null))
            {
                return(null);
            }
            if (ctorColonArguments.Any(a => a == null))
            {
                return(null);
            }

            Attribute result = null;

            foreach (var c in attributeType.GetConstructors())
            {
                var ctorParams    = c.GetParameters();
                var valueSequence = new Lazy <object> [ctorParams.Length];

                if (ctorDirectArguments.Count + ctorColonArguments.Count > ctorParams.Length)
                {
                    return(null);
                }
                for (var i = 0; i < ctorDirectArguments.Count; i++)
                {
                    var value = ctorDirectArguments[i].Item2;
                    if (!ctorParams[i].ParameterType.IsInstanceOfType(value))
                    {
                        return(null);
                    }
                    valueSequence[i] = new Lazy <object>(() => value);
                }
                var remainingCtorParams = ctorParams.Skip(ctorDirectArguments.Count).ToArray();
                for (var i = 0; i < ctorColonArguments.Count; i++)
                {
                    var name           = ctorColonArguments[i].Item1.NameColon.Name.Identifier.ValueText;
                    var value          = ctorColonArguments[i].Item2;
                    var mappedProperty = remainingCtorParams.FirstOrDefault(p => Equals(p.Name, name) && p.ParameterType.IsInstanceOfType(value));
                    if (mappedProperty == null)
                    {
                        return(null);
                    }
                    valueSequence[ctorDirectArguments.Count + i] = new Lazy <object>(() => value);
                }

                for (int i = 0; i < valueSequence.Length; i++)
                {
                    var param = ctorParams[i];
                    var value = valueSequence[i];
                    if (value == null && param.HasDefaultValue)
                    {
                        valueSequence[i] = new Lazy <object>(() => param.DefaultValue);
                    }
                }

                if (valueSequence.Any(v => v == null))
                {
                    return(null);
                }
                try
                {
                    result = c.Invoke(valueSequence.Select(v => v.Value).ToArray()) as Attribute;
                }
                catch (Exception)
                {
                    //Nothing
                }
                //On this stage most possible constructor already found so break anyway
                break;
            }

            if (result == null)
            {
                return(null);
            }

            var namedArguments = attribute.ArgumentList
                                 .Arguments
                                 .SkipWhile(a => a.NameEquals == null)
                                 .Select(a => a.EvaluateExpression())
                                 .ToList();

            if (namedArguments.Any(a => a == null))
            {
                return(null);
            }

            var properties = attributeType.GetProperties();

            foreach (var namedArgument in namedArguments)
            {
                var name     = namedArgument.Item1.NameEquals.Name.Identifier.ValueText;
                var value    = namedArgument.Item2;
                var property = properties.FirstOrDefault(p => p.CanWrite &&
                                                         Equals(p.Name, name) &&
                                                         p.PropertyType.IsInstanceOfType(namedArgument.Item2));
                if (property == null)
                {
                    return(null);
                }

                property.SetValue(result, value);
            }

            return(result);
        }
        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 preceeding "."
                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;
        }