Beispiel #1
0
        private async Task <CsSource> AddMethodMember(CsClass targetClass, CsMethod member, bool logging, bool cdf, bool cdfAspNet, string targetFilePath, NamespaceManager manager)
        {
            CsSource result     = null;
            string   sourceCode = null;

            if (cdfAspNet)
            {
                if (WebApiSupport.IsControllerAction(member))
                {
                    sourceCode = CSharpSourceGenerationCommonDeliveryFramework.GenerateControllerActionMethodSourceCode(member,
                                                                                                                        manager, true, true, CsSecurity.Public, logging, "_logger");
                }
                else
                {
                    sourceCode = CSharpSourceGenerationCommonDeliveryFramework.GenerateStandardMethodSourceCode(member,
                                                                                                                manager, true, true, CsSecurity.Public, logging, "_logger");
                }
            }
            else
            {
                if (cdf)
                {
                    sourceCode = CSharpSourceGenerationCommonDeliveryFramework.GenerateStandardMethodSourceCode(member,
                                                                                                                manager, true, true, CsSecurity.Public, logging, "_logger");
                }
                else
                {
                    if (logging)
                    {
                        sourceCode = CSharpSourceGenerationNetCommon.GenerateStandardMethodSourceCode(member,
                                                                                                      manager, true, true, CsSecurity.Public, true, "_logger");
                    }
                    else
                    {
                        sourceCode = CSharpSourceGenerationCommon.GenerateStandardMethodSourceCode(member,
                                                                                                   manager, true, true);
                    }
                }
            }

            if (string.IsNullOrEmpty(sourceCode))
            {
                throw new CodeFactoryException("Was not able to generate the source code for the member method.");
            }

            result = await targetClass.AddToEndAsync(targetFilePath, CsSourceFormatter.IndentCodeBlock(2, sourceCode));

            if (result == null)
            {
                throw new CodeFactoryException("Could not load the source code after adding the member.");
            }

            return(result);
        }
Beispiel #2
0
        private async Task <CsSource> AddProperty(CsClass targetClass, CsProperty member, string targetFilePath, NamespaceManager manager)
        {
            CsSource result = null;

            string sourceCode = CSharpSourceGenerationCommon.GenerateStandardPropertySourceCode(member, manager);

            if (string.IsNullOrEmpty(sourceCode))
            {
                throw new CodeFactoryException("Was not able to generate the source code for the member property.");
            }

            result = await targetClass.AddToEndAsync(targetFilePath, CsSourceFormatter.IndentCodeBlock(2, sourceCode));

            if (result == null)
            {
                throw new CodeFactoryException("Could not load the source code after adding the member.");
            }

            return(result);
        }
Beispiel #3
0
        private async Task <CsSource> UpdateSubscriptionAsync(CsField subscriptionField, CsClass sourceClass, VsCSharpSource source)
        {
            SourceFormatter formatter        = new SourceFormatter();
            string          injectSourceCode = null;

            var contract = subscriptionField.DataType.GetInterfaceModel();

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

            CsSource sourceCode = source.SourceCode;

            try
            {
                CsClass currentClass = sourceClass;

                var events = contract.Events;

                var subscribePath = ContractHelper.GetSubscribeFilePath(currentClass);


                if (!subscribePath.hasFile)
                {
                    var manager = sourceCode.LoadNamespaceManager(sourceClass.Namespace);

                    var parent = await source.GetParentAsync();

                    if (parent == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }

                    VsDocument generatedDocument  = null;
                    string     partialClassSource = CSharpSourceGenerationCommon.GeneratePartialClass(currentClass, manager);
                    if (parent.ModelType == VisualStudioModelType.ProjectFolder)
                    {
                        var parentFolder = parent as VsProjectFolder;

                        if (parentFolder == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        generatedDocument = await parentFolder.AddDocumentAsync(Path.GetFileName(subscribePath.filePath),
                                                                                partialClassSource);
                    }
                    else
                    {
                        var parentProject = parent as VsProject;

                        if (parentProject == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        generatedDocument = await parentProject.AddDocumentAsync(subscribePath.filePath,
                                                                                 partialClassSource);
                    }
                    sourceCode = await generatedDocument.GetCSharpSourceModelAsync();

                    sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace);

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;

                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }
                else
                {
                    var parent = await source.GetParentAsync();

                    VsCSharpSource sourceDocument = null;
                    if (parent.ModelType == VisualStudioModelType.ProjectFolder)
                    {
                        var parentFolder = parent as VsProjectFolder;

                        if (parentFolder == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        var children = await parentFolder.GetChildrenAsync(false, true);

                        sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                         .Cast <VsCSharpSource>()
                                         .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath);
                    }
                    else
                    {
                        var parentProject = parent as VsProject;

                        if (parentProject == null)
                        {
                            throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                        }

                        var children = await parentProject.GetChildrenAsync(false, true);

                        sourceDocument = children.Where(c => c.ModelType == VisualStudioModelType.CSharpSource)
                                         .Cast <VsCSharpSource>()
                                         .FirstOrDefault(s => s.SourceCode.SourceDocument == subscribePath.filePath);;
                    }

                    if (sourceDocument == null)
                    {
                        throw new CodeFactoryException("Could load the contract document.");
                    }

                    sourceCode = sourceDocument.SourceCode;

                    sourceCode = await sourceCode.AddMissingNamespaces(contract.Events, currentClass.Namespace);

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var namespaceManager = sourceCode.LoadNamespaceManager(currentClass.Namespace);

                foreach (var contractEvent in contract.Events)
                {
                    var eventHandlerName =
                        CSharpSourceGenerationWPF.GenerateContractEventHandlerMethodName(subscriptionField, contractEvent);

                    if (eventHandlerName == null)
                    {
                        throw new CodeFactoryException($"Could not create the source code for a contract event handler.");
                    }

                    if (currentClass.Methods.Any(m => m.Name == eventHandlerName))
                    {
                        continue;
                    }

                    var eventHandlerSource = CSharpSourceGenerationWPF.GenerateContractEventHandlerMethod(subscriptionField, contractEvent,
                                                                                                          namespaceManager);

                    if (eventHandlerSource == null)
                    {
                        throw new CodeFactoryException($"Could not create the source code for the event handler {eventHandlerName}");
                    }

                    sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, eventHandlerSource));

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var subscriptionName   = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethodName(subscriptionField);
                var subscriptionMethod = currentClass.Methods.FirstOrDefault(m => m.Name == subscriptionName);

                if (subscriptionMethod != null)
                {
                    sourceCode = await subscriptionMethod.DeleteAsync();

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var subscriptionSource = CSharpSourceGenerationWPF.GenerateContractSubscriptionMethod(subscriptionField, contract);

                if (subscriptionSource == null)
                {
                    throw new CodeFactoryException("Cannot generate the subscription contract source code.");
                }

                sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, subscriptionSource));

                currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                if (currentClass == null)
                {
                    throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                }

                var releaseName   = CSharpSourceGenerationWPF.GenerateContractReleaseMethodName(subscriptionField);
                var releaseMethod = currentClass.Methods.FirstOrDefault(m => m.Name == releaseName);

                if (releaseMethod != null)
                {
                    sourceCode = await releaseMethod.DeleteAsync();

                    currentClass = sourceCode.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Cannot access the parent of the source code document, cannot update subscription");
                    }
                }

                var releaseSource = CSharpSourceGenerationWPF.GenerateContractReleaseMethod(subscriptionField, contract);

                if (releaseSource == null)
                {
                    throw new CodeFactoryException("Cannot generate the release contract source code.");
                }

                sourceCode = await currentClass.AddToEndAsync(subscribePath.filePath, InjectSourceCodeAtLevel(2, releaseSource));
            }
            catch (CodeFactoryException)
            {
                throw;
            }
            catch (Exception unhandledException)
            {
                throw new CodeFactoryException("The following unhandledException occured", unhandledException);
            }

            return(sourceCode);
        }
Beispiel #4
0
        private async Task <CsSource> AddEvent(CsClass targetClass, CsEvent member, bool isContractMember,
                                               string targetFilePath, NamespaceManager manager)
        {
            CsSource result          = null;
            CsClass  currentClass    = targetClass;
            string   eventSourceCode = null;

            string eventFieldName = null;

            if (isContractMember)
            {
                string fieldPrefix = "_";
                string fieldSuffix = "Handler";

                eventFieldName = $"{fieldPrefix}{member.Name.ConvertToCamelCase()}{fieldSuffix}";

                if (!currentClass.Fields.Any(f => f.Name == eventFieldName))
                {
                    string fieldSource = $"private {member.EventType.CSharpFormatTypeName(manager)} {eventFieldName};";

                    result = await currentClass.AddToBeginningAsync(targetFilePath,
                                                                    CsSourceFormatter.IndentCodeBlock(2, fieldSource));

                    currentClass = result.GetModel(currentClass.LookupPath) as CsClass;
                    if (currentClass == null)
                    {
                        throw new CodeFactoryException("Could not load class data cannot update members.");
                    }
                }

                eventSourceCode = CSharpSourceGenerationCommon.GenerateAddRemoveEvent(member, manager,
                                                                                      CsSecurity.Public, fieldPrefix, fieldSuffix);
            }
            else
            {
                eventSourceCode = CSharpSourceGenerationCommon.GenerateStandardEventSourceCode(member, manager);
            }

            if (string.IsNullOrEmpty(eventSourceCode))
            {
                throw new CodeFactoryException("Could not generate the event source code.");
            }

            result = await currentClass.AddToEndAsync(targetFilePath, CsSourceFormatter.IndentCodeBlock(2, eventSourceCode));

            currentClass = result.GetModel(currentClass.LookupPath) as CsClass;
            if (currentClass == null)
            {
                throw new CodeFactoryException("Could not load class data cannot update members.");
            }

            string raiseEventSourceCode = null;

            if (isContractMember)
            {
                if (string.IsNullOrEmpty(eventFieldName))
                {
                    throw new CodeFactoryException("Event field name was not provided cannot create event handler");
                }

                raiseEventSourceCode = CSharpSourceGenerationCommon.GenerateStandardRaiseEventMethod(member, manager, member.Name,
                                                                                                     CsSecurity.Protected, eventFieldName);
            }
            else
            {
                raiseEventSourceCode = CSharpSourceGenerationCommon.GenerateStandardRaiseEventMethod(member, manager, member.Name,
                                                                                                     CsSecurity.Protected);
            }

            result = await currentClass.AddToEndAsync(targetFilePath,
                                                      CsSourceFormatter.IndentCodeBlock(2, raiseEventSourceCode));

            return(result);
        }
        /// <summary>
        /// Adds the missing members to a target class, that support the common delivery framework implementation..
        /// </summary>
        /// <param name="source">The source code that contains the target class to be updated.</param>
        /// <param name="targetClass">The target class to have the members added to.</param>
        /// <param name="missingMembers">The missing members to be added to the target class.</param>
        /// <param name="boundsCheckLogic">Optional parameter that determines if bounds checking logic should be added to methods. This will default to true.</param>
        /// <param name="loggingLogic">Optional parameter that determines if enter, exit and exception management logic should be added to methods.</param>
        /// <param name="supportAsyncMethods">Optional parameter that determines if methods will use the async keyword when support multi-threaded operations.</param>
        /// <param name="supportsCDFAspNet">Optional parameters that determines if add members support aspnet error handling with CommonDeliveryFramework.</param>
        /// <returns>The updated SourceCode Model once the missing members have been added.</returns>
        /// <exception cref="ArgumentNullException">Thrown if data needed to process a member is not passed.</exception>
        /// <exception cref="CodeFactoryException">Thrown is model data is not valid or a processing error occurs.</exception>
        public static async Task <CsSource> AddMembersToClassWithCDFSupportAsync(CsSource source, CsClass targetClass,
                                                                                 IReadOnlyList <CsMember> missingMembers, bool boundsCheckLogic = true, bool loggingLogic = true, bool supportAsyncMethods = true, bool supportsCDFAspNet = false)
        {
            //Bounds checking to confirm all needed data was passed.
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (targetClass == null)
            {
                throw new ArgumentNullException(nameof(targetClass));
            }
            if (missingMembers == null)
            {
                throw new ArgumentNullException(nameof(missingMembers));
            }

            //Confirming the target models are loaded and are source code
            if (!source.IsLoaded)
            {
                throw new CodeFactoryException("Source code model was not loaded.");
            }
            if (!targetClass.IsLoaded)
            {
                throw new CodeFactoryException("The target class model data is not loaded.");
            }
            if (!targetClass.LoadedFromSource)
            {
                throw new CodeFactoryException("Target class is not loaded from source code cannot update.");
            }

            //If an empty list of missing members was provided then return the original source code
            if (!missingMembers.Any())
            {
                return(source);
            }

            //Variables used to hold the most current version of the code factory models that are being updated.
            CsClass  currentClassModel  = targetClass;
            CsSource currentSourceModel = source;

            currentSourceModel = await currentSourceModel.AddMissingNamespaces(missingMembers, currentClassModel.Namespace);

            currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
            if (currentClassModel == null)
            {
                throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
            }

            //Checking to make sure there is a logger field implemented if not add it to the class.
            currentSourceModel = await currentClassModel.AddMicrosoftExtensionsLoggerFieldAsync(AspNetCoreConstants.FieldNameLogger,
                                                                                                currentSourceModel);

            currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
            if (currentClassModel == null)
            {
                throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
            }


            currentSourceModel = await currentSourceModel.AddUsingStatementAsync(AspNetCoreConstants.CommonDeliveryFrameworkLibraryName);

            currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
            if (currentClassModel == null)
            {
                throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
            }

            if (supportsCDFAspNet)
            {
                //Confirming CDF ASPnet namespace is added to the code file.
                currentSourceModel = await currentSourceModel.AddUsingStatementAsync(AspNetCoreConstants.CommonDeliveryFrameworkAspNetLibraryName);

                currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
                if (currentClassModel == null)
                {
                    throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
                }

                //Confirming the mvc namespace is added to the code file.
                currentSourceModel = await currentSourceModel.AddUsingStatementAsync(AspNetCoreConstants.MvcNamespace);

                currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
                if (currentClassModel == null)
                {
                    throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
                }
            }

            if (supportAsyncMethods)
            {
                //Confirming the mvc namespace is added to the code file.
                currentSourceModel = await currentSourceModel.AddUsingStatementAsync(AspNetCoreConstants.SystemThreadingTasksNamespace);

                currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
                if (currentClassModel == null)
                {
                    throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
                }
            }

            //Loading a namespace manager that will update types definitions to use the correct namespace format. This reads in all the using statements assigned to the class.
            var namespaceManager = source.LoadNamespaceManager(currentClassModel.Namespace);

            bool isControllerClass = currentClassModel.IsController();

            //Processing the missing members
            foreach (var member in missingMembers)
            {
                //Clearing the formatted source code for the member before processing each member
                string sourceCode = null;

                switch (member.MemberType)
                {
                case CsMemberType.Event:

                    //Validating the member event model loaded correctly if not return to the top. No exception will be thrown.
                    if (!(member is CsEvent eventModel))
                    {
                        continue;
                    }

                    //Formatting a default event definition.
                    sourceCode = FormatMemberEvent(eventModel, namespaceManager);

                    break;

                case CsMemberType.Method:

                    //Validating the member event model loaded correctly if not return to the top. No exception will be thrown.
                    if (!(member is CsMethod methodModel))
                    {
                        continue;
                    }

                    bool isControllerAction = false;

                    if (supportsCDFAspNet & isControllerClass)
                    {
                        isControllerAction = IsControllerAction(methodModel);
                    }

                    //Formatting the method implementation based on the optional parameters provided.
                    sourceCode = FormatMemberMethod(methodModel, namespaceManager, loggingLogic, boundsCheckLogic,
                                                    supportAsyncMethods, isControllerAction);

                    break;

                case CsMemberType.Property:

                    //Validating the member property model loaded correctly if not return to the top. No exception will be thrown.
                    if (!(member is CsProperty propertyModel))
                    {
                        continue;
                    }

                    //Formatting a default property definition.
                    sourceCode = FormatMemberProperty(propertyModel, namespaceManager);

                    break;

                default:
                    continue;
                }

                if (string.IsNullOrEmpty(sourceCode))
                {
                    continue;
                }

                //Creating a source formatter and appending the final output with two indent levels to within the body over a class.
                var sourceFormatter = new CodeFactory.SourceFormatter();

                sourceFormatter.AppendCodeBlock(2, sourceCode);

                currentSourceModel = await currentClassModel.AddToEndAsync(sourceFormatter.ReturnSource());

                if (currentSourceModel == null)
                {
                    throw new CodeFactoryException("Cannot load the source code file, cannot complete adding interface members");
                }

                currentClassModel = currentSourceModel.GetModel(currentClassModel.LookupPath) as CsClass;
                if (currentClassModel == null)
                {
                    throw new CodeFactoryException("Cannot load class data, cannot complete adding interface members");
                }
            }

            return(currentSourceModel);
        }