/// <summary> /// Generates the source code for a standard field definition. /// </summary> /// <param name="memberData">Event data to be loaded.</param> /// <param name="manager">The namespace manager to use for namespace management with type declarations.</param> /// <param name="fieldSecurity">Parameter to set the target security for the field.</param> /// <param name="includeKeywords">Optional parameter that will include all keywords assigned to the field from the source model. This is true by default.</param> /// <param name="implementConstant">Determines if the filed is implemented as constant is should be returned as a constant, default is true.</param> /// <param name="requireStaticKeyword">Adds the static keyword to the signature, default is false.</param> /// <param name="requireReadOnlyKeyword">Adds the readonly keyword to the signature, default is false.</param> /// <param name="requireConstant">Implements the field as a constant, default is false.</param> /// <param name="requireConstantValue">The value to set the constant to if required.</param> /// <returns>The fully formatted event source code or null if the member could not be implemented.</returns> public static string GenerateStandardFieldSourceCode(CsField memberData, NamespaceManager manager, CsSecurity fieldSecurity, bool includeKeywords = true, bool implementConstant = true, bool requireStaticKeyword = false, bool requireReadOnlyKeyword = false, bool requireConstant = false, string requireConstantValue = null) { //Bounds checking to make sure all data that is needed is provided. If any required data is missing will return null. if (memberData == null) { return(null); } if (!memberData.IsLoaded) { return(null); } if (manager == null) { return(null); } //C# helper used to format output syntax. var formatter = new CodeFactory.SourceFormatter(); //Using the formatter helper to generate a default event signature. string fieldSyntax = memberData.CSharpFormatFieldDeclaration(manager, includeKeywords, fieldSecurity, implementConstant, requireStaticKeyword, requireReadOnlyKeyword, requireConstant, requireConstantValue); //If the property syntax was not created return. if (string.IsNullOrEmpty(fieldSyntax)) { return(null); } //If the member has document then will build the documentation. if (memberData.HasDocumentation) { //Using a documentation helper that will generate an enumerator that will output all XML documentation for the member. foreach (var documentation in memberData.CSharpFormatXmlDocumentationEnumerator()) { //Appending each xml document line to the being of the member definition. formatter.AppendCodeLine(0, documentation); } } //The member has attributes assigned to it, append the attributes. if (memberData.HasAttributes) { //Using a documentation helper that will generate an enumerator that will output each attribute definition. foreach (var attributeSyntax in memberData.Attributes.CSharpFormatAttributeDeclarationEnumerator(manager)) { //Appending each attribute definition before the member definition. formatter.AppendCodeLine(0, attributeSyntax); } } //Adding the event declaration formatter.AppendCodeBlock(0, fieldSyntax); //Adding a extra line feed at the end of the declaration. formatter.AppendCodeLine(0); //The source formatter returning the final results. return(formatter.ReturnSource()); }
/// <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); }
/// <summary> /// Generates the source code for a standard property definition. That uses a standard getter and setter. /// </summary> /// <param name="memberData">property data to be loaded.</param> /// <param name="manager">The namespace manager to use for namespace management with type declarations.</param> /// <param name="security">The security level to set the source event source code to. Will default to public if not provided.</param> /// <param name="getSecurity">Set the security level of the get accessor if defined for the property, will default to unknown</param> /// <param name="setSecurity">Set the security level of the set accessor if defined for the property, will default to unknown</param> /// <param name="useKeywords">Include the keywords currently assigned to the event model. Default value is to not include them.</param> /// <param name="includeAbstractKeyword">Optional parameter that determines if it will include the definition for the abstract keyword in the definition if it is defined. default is false.</param> /// <param name="requireStaticKeyword">Adds the static keyword to the signature, default is false.</param> /// <param name="requireSealedKeyword">Adds the sealed keyword to the signature, default is false.</param> /// <param name="requireAbstractKeyword">Adds the abstract keyword to the signature, default is false.</param> /// <param name="requireOverrideKeyword">Adds the override keyword to the signature, default is false.</param> /// <param name="requireVirtualKeyword">Adds the virtual keyword to the signature, default is false.</param> /// <returns>The fully formatted event source code or null if the member could not be implemented.</returns> public static string GenerateStandardPropertySourceCode(CsProperty memberData, NamespaceManager manager, bool useKeywords = false, bool includeAbstractKeyword = false, bool requireStaticKeyword = false, bool requireSealedKeyword = false, bool requireAbstractKeyword = false, bool requireOverrideKeyword = false, bool requireVirtualKeyword = false, CsSecurity security = CsSecurity.Public, CsSecurity getSecurity = CsSecurity.Unknown, CsSecurity setSecurity = CsSecurity.Unknown) { //Bounds checking to make sure all data that is needed is provided. If any required data is missing will return null. if (memberData == null) { return(null); } if (!memberData.IsLoaded) { return(null); } if (manager == null) { return(null); } //C# helper used to format output syntax. var formatter = new CodeFactory.SourceFormatter(); //Using the formatter helper to generate a default event signature. string propertySyntax = memberData.CSharpFormatDefaultPropertySignature(manager, useKeywords, includeAbstractKeyword, requireStaticKeyword, requireSealedKeyword, requireAbstractKeyword, requireOverrideKeyword, requireVirtualKeyword, security, setSecurity, getSecurity); //If the property syntax was not created return. if (string.IsNullOrEmpty(propertySyntax)) { return(null); } //If the member has document then will build the documentation. if (memberData.HasDocumentation) { //Using a documentation helper that will generate an enumerator that will output all XML documentation for the member. foreach (var documentation in memberData.CSharpFormatXmlDocumentationEnumerator()) { //Appending each xml document line to the being of the member definition. formatter.AppendCodeLine(0, documentation); } } //The member has attributes assigned to it, append the attributes. if (memberData.HasAttributes) { //Using a documentation helper that will generate an enumerator that will output each attribute definition. foreach (var attributeSyntax in memberData.Attributes.CSharpFormatAttributeDeclarationEnumerator(manager)) { //Appending each attribute definition before the member definition. formatter.AppendCodeLine(0, attributeSyntax); } } //Adding the event declaration formatter.AppendCodeBlock(0, propertySyntax); //Adding a extra line feed at the end of the declaration. formatter.AppendCodeLine(0); //The source formatter returning the final results. return(formatter.ReturnSource()); }