Exemple #1
0
        internal static Type[] GetCherryTypes(Assembly assembly, CherryPickingMethods methods)
        {
            try
            {
                return(assembly.GetTypes().Where(type => (TypeHelper.IsClassOrStruct(type) || type.IsEnum) &&
                                                 CherryPicking.IsCherryType(type, methods)).ToArray());
            }
            catch (ReflectionTypeLoadException e)
            {
                foreach (Exception ex in e.LoaderExceptions)
                {
                    Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assembly.FullName, ex.Message));
                }
            }
            catch (TargetInvocationException e)
            {
                Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assembly.FullName, e.Message + "~~" + e.InnerException.Message));
            }

            return(null);
        }
        /// <summary>
        /// Create TypeScript CodeDOM for POCO types.
        /// For an enum type, all members will be processed regardless of EnumMemberAttribute.
        /// </summary>
        /// <param name="types">POCO types.</param>
        /// <param name="methods">How to cherry pick data to be exposed to the clients.</param>
        /// <param name="clientNamespaceSuffix"></param>
        public void CreateCodeDom(Type[] types, CherryPickingMethods methods, string clientNamespaceSuffix)
        {
            if (types == null)
            {
                throw new ArgumentNullException(nameof(types), "types is not defined.");
            }

            this.pendingTypes.AddRange(types);

            var typeGroupedByNamespace = types
                                         .GroupBy(d => d.Namespace)
                                         .OrderBy(k => k.Key); // order by namespace
            var namespacesOfTypes = typeGroupedByNamespace.Select(d => d.Key).ToArray();

            foreach (var groupedTypes in typeGroupedByNamespace)
            {
                var clientNamespaceText = (groupedTypes.Key + clientNamespaceSuffix);
                var clientNamespace     = new CodeNamespace(clientNamespaceText);
                codeCompileUnit.Namespaces.Add(clientNamespace);                //namespace added to Dom

                Debug.WriteLine("Generating types in namespace: " + groupedTypes.Key + " ...");
                groupedTypes.OrderBy(t => t.Name).Select(type =>
                {
                    var tsName = type.Name;
                    Debug.WriteLine("clientClass: " + clientNamespace + "  " + tsName);

                    CodeTypeDeclaration typeDeclaration;
                    if (TypeHelper.IsClassOrStruct(type))
                    {
                        if (type.IsGenericType)
                        {
                            typeDeclaration = PodGenHelper.CreatePodClientGenericClass(clientNamespace, type);
                        }
                        else
                        {
                            typeDeclaration = type.IsClass ? PodGenHelper.CreatePodClientClass(clientNamespace, tsName) : PodGenHelper.CreatePodClientStruct(clientNamespace, tsName);
                        }

                        if (!type.IsValueType)
                        {
                            if (namespacesOfTypes.Contains(type.BaseType.Namespace))
                            {
                                typeDeclaration.BaseTypes.Add(RefineCustomComplexTypeText(type.BaseType));
                            }
                            else
                            {
                                typeDeclaration.BaseTypes.Add(type.BaseType);
                            }
                        }

                        CreateTypeDocComment(type, typeDeclaration);

                        var typeCherryMethods = CherryPicking.GetTypeCherryMethods(type);
                        bool withDataContract = (typeCherryMethods & CherryPickingMethods.DataContract) == CherryPickingMethods.DataContract;
                        var typeProperties    = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(p => p.Name).ToArray();
                        foreach (var propertyInfo in typeProperties)
                        {
                            var cherryType = CherryPicking.GetMemberCherryType(propertyInfo, methods, withDataContract);
                            if (cherryType == CherryType.None)
                            {
                                continue;
                            }
                            string tsPropertyName;


                            //todo: Maybe the required of JsonMemberAttribute?       var isRequired = cherryType == CherryType.BigCherry;
                            tsPropertyName = propertyInfo.Name;                            //todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
                            Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, propertyInfo.PropertyType.Name));
                            var defaultValue = GetDefaultValue(propertyInfo.GetCustomAttribute(typeOfDefaultValueAttribute) as DefaultValueAttribute);

                            //var clientProperty = new CodeMemberProperty() //orthodox way of creating property, but resulting in verbose generated codes
                            //{
                            // Name = tsPropertyName,
                            // Type = TranslateToClientTypeReference(propertyInfo.PropertyType),
                            // Attributes = MemberAttributes.Public | MemberAttributes.Final,
                            //};
                            var clientProperty = CreateProperty(tsPropertyName, propertyInfo.PropertyType, defaultValue);                             //hacky way of creating clean getter and writter.

                            var isRequired = cherryType == CherryType.BigCherry;
                            if (isRequired)
                            {
                                clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute"));
                            }

                            //var privateFieldName = "_" + tsPropertyName;

                            //typeDeclaration.Members.Add(new CodeMemberField()
                            //{
                            // Name = privateFieldName,
                            // Type = TranslateToClientTypeReference(propertyInfo.PropertyType),
                            //});

                            //clientProperty.GetStatements.Add(new CodeSnippetStatement($"\t\t\t\treturn {privateFieldName};"));
                            //clientProperty.SetStatements.Add(new CodeSnippetStatement($"\t\t\t\t{privateFieldName} = value;"));

                            if (settings.DataAnnotationsEnabled)
                            {
                                AddValidationAttributes(propertyInfo, clientProperty, isRequired);
                            }

                            CreatePropertyDocComment(propertyInfo, clientProperty);

                            if (settings.DecorateDataModelWithDataContract)
                            {
                                clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember"));
                            }

                            typeDeclaration.Members.Add(clientProperty);
                        }

                        var typeFields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(f => f.Name).ToArray();
                        foreach (var fieldInfo in typeFields)
                        {
                            var cherryType = CherryPicking.GetMemberCherryType(fieldInfo, methods, withDataContract);
                            if (cherryType == CherryType.None)
                            {
                                continue;
                            }
                            string tsPropertyName;


                            tsPropertyName = fieldInfo.Name;                            //todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
                            Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, fieldInfo.FieldType.Name));
                            var defaultValue = GetDefaultValue(fieldInfo.GetCustomAttribute(typeOfDefaultValueAttribute) as DefaultValueAttribute);

                            //public fields of a class will be translated into properties
                            if (type.IsClass)
                            {
                                //var clientProperty = new CodeMemberProperty() //orthodox way of creating property, but resulting in verbose generated codes
                                //{
                                // Name = tsPropertyName,
                                // Type = TranslateToClientTypeReference(fieldInfo.FieldType),
                                // Attributes = MemberAttributes.Public | MemberAttributes.Final,
                                //};

                                var clientProperty = CreateProperty(tsPropertyName, fieldInfo.FieldType, defaultValue);                                 //hacky way of creating clean getter and writter.

                                var isRequired = cherryType == CherryType.BigCherry;
                                if (isRequired)
                                {
                                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute"));
                                }

                                //var privateFieldName = "_" + tsPropertyName;

                                //typeDeclaration.Members.Add(new CodeMemberField()
                                //{
                                // Name = privateFieldName,
                                // Type = TranslateToClientTypeReference(fieldInfo.FieldType),
                                //});

                                //clientProperty.GetStatements.Add(new CodeSnippetStatement($"\t\t\t\treturn {privateFieldName};"));
                                //clientProperty.SetStatements.Add(new CodeSnippetStatement($"\t\t\t\t{privateFieldName} = value;"));

                                if (settings.DataAnnotationsEnabled)
                                {
                                    AddValidationAttributes(fieldInfo, clientProperty, isRequired);
                                }

                                CreateFieldDocComment(fieldInfo, clientProperty);

                                if (settings.DecorateDataModelWithDataContract)
                                {
                                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember"));
                                }

                                typeDeclaration.Members.Add(clientProperty);
                            }
                            else                             //public fields of struct
                            {
                                var clientField = new CodeMemberField()
                                {
                                    Name       = tsPropertyName,
                                    Type       = TranslateToClientTypeReference(fieldInfo.FieldType),
                                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                                    //todo: add some attributes
                                };

                                CreateFieldDocComment(fieldInfo, clientField);

                                if (settings.DecorateDataModelWithDataContract)
                                {
                                    clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember"));
                                }

                                typeDeclaration.Members.Add(clientField);
                            }
                        }

                        if (settings.DecorateDataModelWithDataContract)
                        {
                            typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataContract", new CodeAttributeArgument("Namespace", new CodeSnippetExpression($"\"{settings.DataContractNamespace}\""))));
                        }

                        if (settings.DecorateDataModelWithSerializable)
                        {
                            typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.SerializableAttribute"));
                        }
                    }
                    else if (type.IsEnum)
                    {
                        typeDeclaration = PodGenHelper.CreatePodClientEnum(clientNamespace, tsName);

                        CreateTypeDocComment(type, typeDeclaration);

                        int k = 0;
                        foreach (var fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static))                        //not to sort
                        {
                            var name     = fieldInfo.Name;
                            var intValue = (int)Convert.ChangeType(fieldInfo.GetValue(null), typeof(int));
                            Debug.WriteLine(name + " -- " + intValue);
                            var isInitialized = intValue != k;

                            var clientField = new CodeMemberField()
                            {
                                Name           = name,
                                Type           = new CodeTypeReference(fieldInfo.FieldType),
                                InitExpression = isInitialized ? new CodePrimitiveExpression(intValue) : null,
                            };

                            CreateFieldDocComment(fieldInfo, clientField);

                            if (settings.DecorateDataModelWithDataContract)
                            {
                                clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                            }

                            typeDeclaration.Members.Add(clientField);
                            k++;
                        }

                        if (settings.DecorateDataModelWithDataContract)
                        {
                            typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataContract", new CodeAttributeArgument("Namespace", new CodeSnippetExpression($"\"{settings.DataContractNamespace}\""))));
                        }

                        if (settings.DecorateDataModelWithSerializable)
                        {
                            typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.SerializableAttribute"));
                        }
                    }
                    else
                    {
                        Trace.TraceWarning("Not yet supported: " + type.Name);
                        typeDeclaration = null;
                    }

                    return(typeDeclaration);
                }
                                                         ).ToArray();//add classes into the namespace
            }
        }
        /// <summary>
        /// Create TypeScript CodeDOM for POCO types.
        /// For an enum type, all members will be processed regardless of EnumMemberAttribute.
        /// </summary>
        /// <param name="types">POCO types.</param>
        /// <param name="methods">How to cherry pick data to be exposed to the clients.</param>
        public void CreateCodeDom(Type[] types, CherryPickingMethods methods)
        {
            if (types == null)
            {
                throw new ArgumentNullException("types", "types is not defined.");
            }

            this.pendingTypes.AddRange(types);
            var typeGroupedByNamespace = types.GroupBy(d => d.Namespace);
            var namespacesOfTypes      = typeGroupedByNamespace.Select(d => d.Key).ToArray();

            foreach (var groupedTypes in typeGroupedByNamespace)
            {
                var clientNamespaceText = (groupedTypes.Key + ".Client");
                var clientNamespace     = new CodeNamespace(clientNamespaceText);
                targetUnit.Namespaces.Add(clientNamespace);//namespace added to Dom

                Debug.WriteLine("Generating types in namespace: " + groupedTypes.Key + " ...");
                groupedTypes.Select(type =>
                {
                    var tsName = type.Name;
                    Debug.WriteLine("clientClass: " + clientNamespace + "  " + tsName);

                    CodeTypeDeclaration typeDeclaration;
                    if (TypeHelper.IsClassOrStruct(type))
                    {
                        typeDeclaration = type.IsClass ? PodGenHelper.CreatePodClientClass(clientNamespace, tsName): PodGenHelper.CreatePodClientStruct(clientNamespace, tsName);

                        if (!type.IsValueType)
                        {
                            if (namespacesOfTypes.Contains(type.BaseType.Namespace))
                            {
                                typeDeclaration.BaseTypes.Add(RefineCustomComplexTypeText(type.BaseType));
                            }
                            else
                            {
                                typeDeclaration.BaseTypes.Add(type.BaseType);
                            }
                        }

                        CreateTypeDocComment(type, typeDeclaration);

                        foreach (var propertyInfo in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
                        {
                            var cherryType = CherryPicking.GetMemberCherryType(propertyInfo, methods);
                            if (cherryType == CherryType.None)
                            {
                                continue;
                            }
                            string tsPropertyName;


                            //todo: Maybe the required of JsonMemberAttribute?       var isRequired = cherryType == CherryType.BigCherry;
                            tsPropertyName = propertyInfo.Name;//todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
                            Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, propertyInfo.PropertyType.Name));


                            var clientProperty = new CodeMemberProperty()
                            {
                                Name       = tsPropertyName,
                                Type       = TranslateToClientTypeReference(propertyInfo.PropertyType),
                                Attributes = MemberAttributes.Public | MemberAttributes.Final,
                                //todo: add some attributes
                            };

                            var isRequired = cherryType == CherryType.BigCherry;
                            if (isRequired)
                            {
                                clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute"));
                            }

                            var privateFieldName = "_" + tsPropertyName;

                            typeDeclaration.Members.Add(new CodeMemberField()
                            {
                                Name = privateFieldName,
                                Type = TranslateToClientTypeReference(propertyInfo.PropertyType),
                            });

                            clientProperty.GetStatements.Add(new CodeSnippetStatement($"                return {privateFieldName};"));
                            clientProperty.SetStatements.Add(new CodeSnippetStatement($"                {privateFieldName} = value;"));

                            CreatePropertyDocComment(propertyInfo, clientProperty);

                            typeDeclaration.Members.Add(clientProperty);
                        }

                        foreach (var fieldInfo in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
                        {
                            var cherryType = CherryPicking.GetMemberCherryType(fieldInfo, methods);
                            if (cherryType == CherryType.None)
                            {
                                continue;
                            }
                            string tsPropertyName;


                            tsPropertyName = fieldInfo.Name;//todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
                            Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, fieldInfo.FieldType.Name));

                            //public fields of a class will be translated into properties
                            if (type.IsClass)
                            {
                                var clientProperty = new CodeMemberProperty()
                                {
                                    Name       = tsPropertyName,
                                    Type       = TranslateToClientTypeReference(fieldInfo.FieldType),
                                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                                    //todo: add some attributes
                                };

                                var isRequired = cherryType == CherryType.BigCherry;
                                if (isRequired)
                                {
                                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute"));
                                }

                                var privateFieldName = "_" + tsPropertyName;

                                typeDeclaration.Members.Add(new CodeMemberField()
                                {
                                    Name = privateFieldName,
                                    Type = TranslateToClientTypeReference(fieldInfo.FieldType),
                                });

                                clientProperty.GetStatements.Add(new CodeSnippetStatement($"                return {privateFieldName};"));
                                clientProperty.SetStatements.Add(new CodeSnippetStatement($"                {privateFieldName} = value;"));

                                CreateFieldDocComment(fieldInfo, clientProperty);

                                typeDeclaration.Members.Add(clientProperty);
                            }
                            else //public fields of struct
                            {
                                var clientField = new CodeMemberField()
                                {
                                    Name       = tsPropertyName,
                                    Type       = TranslateToClientTypeReference(fieldInfo.FieldType),
                                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                                    //todo: add some attributes
                                };

                                CreateFieldDocComment(fieldInfo, clientField);

                                typeDeclaration.Members.Add(clientField);
                            }
                        }
                    }
                    else if (type.IsEnum)
                    {
                        typeDeclaration = PodGenHelper.CreatePodClientEnum(clientNamespace, tsName);

                        CreateTypeDocComment(type, typeDeclaration);

                        int k = 0;
                        foreach (var fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static))
                        {
                            var name     = fieldInfo.Name;
                            var intValue = (int)Convert.ChangeType(fieldInfo.GetValue(null), typeof(int));
                            Debug.WriteLine(name + " -- " + intValue);
                            var isInitialized = intValue != k;

                            var clientField = new CodeMemberField()
                            {
                                Name           = name,
                                Type           = new CodeTypeReference(fieldInfo.FieldType),
                                InitExpression = isInitialized ? new CodePrimitiveExpression(intValue) : null,
                            };

                            CreateFieldDocComment(fieldInfo, clientField);

                            typeDeclaration.Members.Add(clientField);
                            k++;
                        }
                    }
                    else
                    {
                        Trace.TraceWarning("Not yet supported: " + type.Name);
                        typeDeclaration = null;
                    }

                    return(typeDeclaration);
                }
                                    ).ToArray();//add classes into the namespace
            }
        }