public static void ProcessFields(Type definitionType, DefinitionSchema schema, IList <string> hiddenTags, Stack <Type> typesStack) { var properties = definitionType.GetFields(); foreach (var fieldInfo in properties) { DefinitionProperty prop = ProcessField(fieldInfo, hiddenTags, typesStack); if (prop == null) { continue; } if (prop.TypeFormat.Type == ParameterType.Array) { Type propType = fieldInfo.FieldType; Type t = propType.GetElementType() ?? DefinitionsBuilder.GetEnumerableType(propType); if (t != null) { //prop.TypeFormat = new TypeFormat(prop.TypeFormat.Type, HttpUtility.HtmlEncode(t.FullName)); prop.TypeFormat = new TypeFormat(prop.TypeFormat.Type, null); TypeFormat st = Helpers.MapSwaggerType(t); if (st.Type == ParameterType.Array || st.Type == ParameterType.Object) { prop.Items.TypeFormat = new TypeFormat(ParameterType.Unknown, null); prop.Items.Ref = t.GetModelName(); } else { prop.Items.TypeFormat = st; } } } if (prop.Required) { if (schema.Required == null) { schema.Required = new List <string>(); } schema.Required.Add(prop.Title); } schema.Properties.Add(prop); } }
private Schema BuildSchema(Type type, IList <Type> definitionsTypesList) { if (type == typeof(void)) { return(null); } if (type.BaseType == typeof(System.Threading.Tasks.Task)) { type = GetTaskInnerType(type); } TypeFormat typeFormat = Helpers.MapSwaggerType(type, definitionsTypesList); switch (typeFormat.Type) { case ParameterType.Object: return(new Schema { Ref = typeFormat.Format }); case ParameterType.Array: Type t = type.GetElementType() ?? GetEnumerableType(type); if (t == null) { return(null); } definitionsTypesList.Add(t); return(new Schema { TypeFormat = typeFormat, Ref = HttpUtility.HtmlEncode(t.FullName) }); default: definitionsTypesList.Add(type); return(new Schema { TypeFormat = typeFormat }); } }
private static Definition ConvertTypeToDefinition(Type definitionType, IList <string> hiddenTags, Stack <Type> typesStack) { DefinitionSchema schema = new DefinitionSchema { Name = definitionType.FullName }; ProcessTypeAttributes(definitionType, schema); // process schema.TypeFormat = Helpers.MapSwaggerType(definitionType, null); if (schema.TypeFormat.Type == ParameterType.String && schema.TypeFormat.Format == "enum") { schema.Enum = new List <string>(); List <string> listOfEnumNames = definitionType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { schema.Enum.Add(GetEnumMemberValue(definitionType, enumName)); } } else if (schema.TypeFormat.Type == ParameterType.Array) { Type t = GetEnumerableType(definitionType); if (t != null) { schema.Ref = t.FullName; typesStack.Push(t); } } else { ProcessProperties(definitionType, schema, hiddenTags, typesStack); } return(new Definition { Schema = schema }); }
private static DefinitionProperty ProcessField(FieldInfo propertyInfo, IList <string> hiddenTags, Stack <Type> typesStack) { if (propertyInfo.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || propertyInfo.GetCustomAttributes <SwaggerWcfTagAttribute>() .Select(t => t.TagName) .Any(hiddenTags.Contains)) { return(null); } TypeFormat typeFormat = Helpers.MapSwaggerType(propertyInfo.FieldType, null); DefinitionProperty prop = new DefinitionProperty { Title = propertyInfo.Name }; DataMemberAttribute dataMemberAttribute = propertyInfo.GetCustomAttribute <DataMemberAttribute>(); if (dataMemberAttribute != null) { if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) { prop.Title = dataMemberAttribute.Name; } prop.Required = dataMemberAttribute.IsRequired; } // Special case - if it came out required, but we unwrapped a null-able type, // then it's necessarily not required. Ideally this would only set the default, // but we can't tell the difference between an explicit declaration of // IsRequired =false on the DataMember attribute and no declaration at all. if (prop.Required && propertyInfo.FieldType.IsGenericType && propertyInfo.FieldType.GetGenericTypeDefinition() == typeof(Nullable <>)) { prop.Required = false; } DescriptionAttribute descriptionAttribute = propertyInfo.GetCustomAttribute <DescriptionAttribute>(); if (descriptionAttribute != null) { prop.Description = descriptionAttribute.Description; } SwaggerWcfRegexAttribute regexAttr = propertyInfo.GetCustomAttribute <SwaggerWcfRegexAttribute>(); if (regexAttr != null) { prop.Pattern = regexAttr.Regex; } prop.TypeFormat = typeFormat; if (prop.TypeFormat.Type == ParameterType.Object) { typesStack.Push(propertyInfo.FieldType); prop.Ref = propertyInfo.FieldType.GetModelName(); return(prop); } if (prop.TypeFormat.Type == ParameterType.Array) { Type subType = DefinitionsBuilder.GetEnumerableType(propertyInfo.FieldType); if (subType != null) { TypeFormat subTypeFormat = Helpers.MapSwaggerType(subType, null); if (subTypeFormat.Type == ParameterType.Object) { typesStack.Push(subType); } prop.Items = new ParameterItems { TypeFormat = subTypeFormat }; } } if ((prop.TypeFormat.Type == ParameterType.Integer && prop.TypeFormat.Format == "enum") || (prop.TypeFormat.Type == ParameterType.Array && prop.Items.TypeFormat.Format == "enum")) { prop.Enum = new List <int>(); Type propType = propertyInfo.FieldType; if (propType.IsGenericType && (propType.GetGenericTypeDefinition() == typeof(Nullable <>) || propType.GetGenericTypeDefinition() == typeof(List <>))) { propType = propType.GetEnumerableType(); } string enumDescription = ""; List <string> listOfEnumNames = propType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { var enumMemberItem = Enum.Parse(propType, enumName, true); string enumMemberDescription = DefinitionsBuilder.GetEnumDescription((Enum)enumMemberItem); enumMemberDescription = (string.IsNullOrWhiteSpace(enumMemberDescription)) ? "" : $"({enumMemberDescription})"; int enumMemberValue = DefinitionsBuilder.GetEnumMemberValue(propType, enumName); if (prop.Description != null) { prop.Enum.Add(enumMemberValue); } enumDescription += $" {enumName}{System.Web.HttpUtility.HtmlEncode(" = ")}{enumMemberValue} {enumMemberDescription}\r\n"; } if (enumDescription != "") { prop.Description += $"\r\n\r\n{enumDescription}"; } } // Apply any options set in a [SwaggerWcfProperty] DefinitionsBuilder.ApplyAttributeOptions(propertyInfo, prop); return(prop); }
private Schema BuildSchema(Type type, MethodInfo implementation, MethodInfo declaration, bool wrappedResponse, IList <Type> definitionsTypesList) { if (type == typeof(void) || type == typeof(Task)) { return(null); } if (type.BaseType == typeof(Task)) { type = GetTaskInnerType(type); } TypeFormat typeFormat; if (wrappedResponse) { string funcName = implementation.Name; string typeName = implementation.GetCustomAttribute <SwaggerWcfReturnTypeAttribute>()?.Name ?? declaration.GetCustomAttribute <SwaggerWcfReturnTypeAttribute>()?.Name ?? funcName + "Result"; TypeBuilder typeBuilder = new TypeBuilder(typeName + "Wrapper"); typeBuilder.AddField(typeName, type, true); typeFormat = Helpers.MapSwaggerType(typeBuilder.Type, definitionsTypesList); } else { typeFormat = Helpers.MapSwaggerType(type, definitionsTypesList); } switch (typeFormat.Type) { case ParameterType.Object: return(new Schema { Ref = typeFormat.Format }); case ParameterType.Array: Type t = type.GetElementType() ?? GetEnumerableType(type); if (t == null) { return(null); } TypeFormat arrayTypeFormat = Helpers.MapSwaggerType(t); if (arrayTypeFormat.IsPrimitiveType) { return(new Schema { TypeFormat = typeFormat, ArrayTypeFormat = arrayTypeFormat }); } else { definitionsTypesList.Add(t); return(new Schema { TypeFormat = typeFormat, Ref = HttpUtility.HtmlEncode(t.GetModelName()) }); } default: definitionsTypesList.Add(type); return(new Schema { TypeFormat = typeFormat }); } }
private ParameterBase GetParameter(TypeFormat typeFormat, MethodInfo declaration, MethodInfo implementation, ParameterInfo parameter, SwaggerWcfParameterAttribute settings, string uriTemplate, bool wrappedRequest, IList <Type> definitionsTypesList, InType inType) { string description = settings?.Description; bool required = settings != null && settings.Required; string name = inType == InType.Query ? ResolveParameterNameFromUri(uriTemplate, parameter) : parameter.Name; if (inType == InType.Path) { required = true; } if (!required && !parameter.HasDefaultValue) { required = true; } Type paramType = settings == null || settings.ParameterType == null ? parameter.ParameterType : settings.ParameterType; if (paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable <>)) { required = false; paramType = paramType.GenericTypeArguments[0]; } if (typeFormat.Type == ParameterType.Object) { return(new ParameterSchema { Name = name, Description = description, In = inType, Required = required, SchemaRef = typeFormat.Format }); } if (inType == InType.Body) { if (typeFormat.Type == ParameterType.Array) { Type t = paramType.GetElementType() ?? GetEnumerableType(paramType); TypeFormat subTypeFormat = Helpers.MapSwaggerType(t); ParameterItems items; if (subTypeFormat.IsPrimitiveType || subTypeFormat.IsEnum) { items = new ParameterItems { TypeFormat = subTypeFormat }; } else { items = new ParameterItems { Items = new ParameterSchema { SchemaRef = t.GetModelName() } }; } ParameterPrimitive arrayParam = new ParameterPrimitive { Name = name, Description = description, In = inType, Required = required, TypeFormat = typeFormat, Items = items, CollectionFormat = CollectionFormat.Csv }; //it's a complex type, so we'll need to map it later if (definitionsTypesList != null && !definitionsTypesList.Contains(t)) { definitionsTypesList.Add(t); } return(arrayParam); } if (typeFormat.IsPrimitiveType || typeFormat.IsEnum) { bool isGetRequest = implementation.GetCustomAttributes <WebGetAttribute>().Any() || declaration.GetCustomAttributes <WebGetAttribute>().Any(); if (!isGetRequest) { WebInvokeAttribute webInvoke = implementation.GetCustomAttribute <WebInvokeAttribute>() ?? declaration.GetCustomAttribute <WebInvokeAttribute>(); if (webInvoke != null && webInvoke.Method == "GET") { isGetRequest = true; } } if (!wrappedRequest && isGetRequest) { ParameterPrimitive paramPrimitive = new ParameterPrimitive { Name = name, Description = description, In = InType.Query, Required = required, TypeFormat = typeFormat }; return(paramPrimitive); } else { ParameterPrimitive paramPrimitive = new ParameterPrimitive { Name = name, Description = description, In = inType, Required = required, TypeFormat = typeFormat }; return(paramPrimitive); } } //it's a complex type, so we'll need to map it later if (definitionsTypesList != null && !definitionsTypesList.Contains(paramType)) { definitionsTypesList.Add(paramType); } typeFormat = new TypeFormat(ParameterType.Object, HttpUtility.HtmlEncode(paramType.GetModelName())); return(new ParameterSchema { Name = name, Description = description, In = inType, Required = required, SchemaRef = typeFormat.Format }); } ParameterPrimitive param = new ParameterPrimitive { Name = name, Description = description, In = inType, Required = required, TypeFormat = typeFormat }; return(param); }
internal IEnumerable <Tuple <string, PathAction> > GetActions(MethodInfo[] targetMethods, MethodInfo[] interfaceMethods, IList <Type> definitionsTypesList) { int methodsCounts = interfaceMethods.Length; for (int index = 0; index < methodsCounts; index++) { MethodInfo implementation = targetMethods[index]; MethodInfo declaration = interfaceMethods[index]; //if a tag from either implementation or declaration is marked as not visible, skip it List <SwaggerWcfTagAttribute> methodTags = implementation.GetCustomAttributes <SwaggerWcfTagAttribute>().ToList(); methodTags = methodTags.Concat(declaration.GetCustomAttributes <SwaggerWcfTagAttribute>()).ToList(); methodTags = methodTags.Distinct().ToList(); // If no tags on the method - check declared Type/Interface itself if (methodTags.Count < 1) { methodTags = implementation.DeclaringType.GetCustomAttributes <SwaggerWcfTagAttribute>() .Concat(declaration.DeclaringType.GetCustomAttributes <SwaggerWcfTagAttribute>()) .ToList(); } if ((methodTags.Count == 0 && HiddenTags.Contains("default")) || methodTags.Any(t => HiddenTags.Contains(t.TagName))) { continue; } //if the method is marked Hidden anywhere, skip it (even if methods tags listed as visible). if ((implementation.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || declaration.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null) ) { continue; } //find the WebGet/Invoke attributes, or skip if neither is present WebGetAttribute wg = declaration.GetCustomAttribute <WebGetAttribute>(); WebInvokeAttribute wi = declaration.GetCustomAttribute <WebInvokeAttribute>(); if (wg == null && wi == null) { continue; } string httpMethod = (wi == null) ? "GET" : wi.Method ?? "POST"; string uriTemplate = GetUriTemplate(wi, wg, declaration); bool wrappedRequest = IsRequestWrapped(wg, wi); bool wrappedResponse = IsResponseWrapped(wg, wi); var wcfPathAttribute = (implementation.GetCustomAttribute(typeof(SwaggerWcfPathAttribute), false) as SwaggerWcfPathAttribute) ?? (declaration.GetCustomAttribute(typeof(SwaggerWcfPathAttribute), false) as SwaggerWcfPathAttribute); int sortOrder = (wcfPathAttribute?.SortOrder).GetValueOrDefault(); //implementation description overrides interface description string description = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "Description") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "Description") ?? Helpers.GetCustomAttributeValue <string, DescriptionAttribute>(implementation, "Description") ?? Helpers.GetCustomAttributeValue <string, DescriptionAttribute>(declaration, "Description") ?? ""; string summary = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "Summary") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "Summary") ?? ""; string operationId = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "OperationId") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "OperationId") ?? ""; if (operationId == "") { if (implementation.DeclaringType != null) { operationId = implementation.DeclaringType.FullName + "."; } operationId += implementation.Name; } string externalDocsDescription = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "ExternalDocsDescription") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "ExternalDocsDescription") ?? ""; string externalDocsUrl = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "ExternalDocsUrl") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "ExternalDocsUrl") ?? ""; ExternalDocumentation externalDocs = null; if (!string.IsNullOrWhiteSpace(externalDocsDescription) || !string.IsNullOrWhiteSpace(externalDocsUrl)) { externalDocs = new ExternalDocumentation { Description = externalDocsDescription, Url = HttpUtility.HtmlEncode(externalDocsUrl) }; } bool deprecated = Helpers.GetCustomAttributeValue <SwaggerWcfPathAttribute>(implementation, "Deprecated"); if (!deprecated) { deprecated = Helpers.GetCustomAttributeValue <SwaggerWcfPathAttribute>(declaration, "Deprecated"); } string operationPath = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "OperationPath") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "OperationPath"); if (!string.IsNullOrWhiteSpace(operationPath)) { uriTemplate = ConcatPaths(operationPath, uriTemplate); } PathAction operation = new PathAction { Id = httpMethod.ToLowerInvariant(), SortOrder = sortOrder, Summary = summary, Description = description, Tags = methodTags.Where(t => !t.HideFromSpec).Select(t => HttpUtility.HtmlEncode(t.TagName)).ToList(), Consumes = new List <string>(GetConsumes(implementation, declaration)), Produces = new List <string>(GetProduces(implementation, declaration)), Deprecated = deprecated, OperationId = HttpUtility.HtmlEncode(operationId), ExternalDocs = externalDocs, Responses = GetResponseCodes(implementation, declaration, wrappedResponse, definitionsTypesList), Security = GetMethodSecurity(implementation, declaration) // Schemes = TODO: how to get available schemes for this WCF service? (schemes: http/https) }; //try to map each implementation parameter to the uriTemplate. ParameterInfo[] parameters = declaration.GetParameters(); if (parameters.Any()) { operation.Parameters = new List <ParameterBase>(); } List <SwaggerWcfHeaderAttribute> headers = implementation.GetCustomAttributes <SwaggerWcfHeaderAttribute>().ToList(); headers = headers.Concat(declaration.GetCustomAttributes <SwaggerWcfHeaderAttribute>()).ToList(); // remove duplicates headers = headers.GroupBy(h => h.Name).Select(g => g.First()).ToList(); // parameters - headers foreach (SwaggerWcfHeaderAttribute attr in headers) { operation.Parameters.Add(new ParameterPrimitive { Name = attr.Name, Description = attr.Description, Default = attr.DefaultValue, In = InType.Header, Required = attr.Required, TypeFormat = new TypeFormat(ParameterType.String, null) }); } bool isGetRequest = httpMethod == "GET"; int bodyParameterCount = parameters.Where(p => GetInType(uriTemplate, p.Name) == InType.Body).Count(); TypeBuilder typeBuilder = null; if (!wrappedRequest && !isGetRequest && bodyParameterCount > 1) { wrappedRequest = true; } if (wrappedRequest) { typeBuilder = new TypeBuilder(implementation.GetWrappedName(declaration)); } var declarationName = declaration.Name; foreach (ParameterInfo parameter in parameters) { SwaggerWcfParameterAttribute settings = implementation.GetParameters() .First(p => p.Position.Equals(parameter.Position)) .GetCustomAttribute <SwaggerWcfParameterAttribute>() ?? parameter.GetCustomAttribute <SwaggerWcfParameterAttribute>(); if (implementation.GetParameters() .First(p => p.Position.Equals(parameter.Position)) .GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || parameter.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null) { continue; } List <SwaggerWcfTagAttribute> piTags = methodTags.Concat(parameter.GetCustomAttributes <SwaggerWcfTagAttribute>()) .ToList(); InType inType = GetInType(uriTemplate, parameter.Name); if (inType == InType.Body && wrappedRequest) { bool required = settings != null && settings.Required; if (!required && !parameter.HasDefaultValue) { required = true; } typeBuilder.AddField(parameter.Name, parameter.ParameterType, required); continue; } if (piTags.Any(t => HiddenTags.Contains(t.TagName))) { continue; } Type type = settings == null || settings.ParameterType == null ? parameter.ParameterType : settings.ParameterType; TypeFormat typeFormat = Helpers.MapSwaggerType(type, definitionsTypesList); operation.Parameters.Add(GetParameter(typeFormat, declaration, implementation, parameter, settings, uriTemplate, wrappedRequest, definitionsTypesList, inType)); } if (wrappedRequest) { TypeFormat typeFormat = Helpers.MapSwaggerType(typeBuilder.Type, definitionsTypesList); operation.Parameters.Add(new ParameterSchema { Name = implementation.GetWrappedName(declaration) + "Wrapper", In = InType.Body, Required = true, SchemaRef = typeFormat.Format }); } if (!string.IsNullOrWhiteSpace(uriTemplate)) { int indexOfQuestionMark = uriTemplate.IndexOf('?'); if (indexOfQuestionMark >= 0) { uriTemplate = uriTemplate.Substring(0, indexOfQuestionMark); } uriTemplate = RemoveParametersDefaultValuesFromUri(uriTemplate); } yield return(new Tuple <string, PathAction>(uriTemplate, operation)); } }
private static DefinitionProperty ProcessProperty(PropertyInfo propertyInfo, IList <string> hiddenTags, Stack <Type> typesStack) { if (propertyInfo.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || propertyInfo.GetCustomAttributes <SwaggerWcfTagAttribute>() .Select(t => t.TagName) .Any(hiddenTags.Contains)) { return(null); } TypeFormat typeFormat = Helpers.MapSwaggerType(propertyInfo.PropertyType, null); DefinitionProperty prop = new DefinitionProperty { Title = propertyInfo.Name }; DataMemberAttribute dataMemberAttribute = propertyInfo.GetCustomAttribute <DataMemberAttribute>(); if (dataMemberAttribute != null) { if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) { prop.Title = dataMemberAttribute.Name; } prop.Required = dataMemberAttribute.IsRequired; } // Special case - if it came out required, but we unwrapped a null-able type, // then it's necessarily not required. Ideally this would only set the default, // but we can't tell the difference between an explicit delaration of // IsRequired =false on the DataMember attribute and no declaration at all. if (prop.Required && propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable <>)) { prop.Required = false; } DescriptionAttribute descriptionAttribute = propertyInfo.GetCustomAttribute <DescriptionAttribute>(); if (descriptionAttribute != null) { prop.Description = descriptionAttribute.Description; } prop.TypeFormat = typeFormat; if (prop.TypeFormat.Type == ParameterType.Object) { typesStack.Push(propertyInfo.PropertyType); prop.Ref = propertyInfo.PropertyType.FullName; return(prop); } if (prop.TypeFormat.Type == ParameterType.Array) { Type subType = GetEnumerableType(propertyInfo.PropertyType); if (subType != null) { TypeFormat subTypeFormat = Helpers.MapSwaggerType(subType, null); if (subTypeFormat.Type == ParameterType.Object) { typesStack.Push(subType); } prop.Items = new ParameterItems { TypeFormat = subTypeFormat }; } } if (prop.TypeFormat.Type == ParameterType.String && prop.TypeFormat.Format == "enum") { prop.Enum = new List <string>(); Type propType = propertyInfo.PropertyType; if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable <>)) { propType = propType.GetEnumerableType(); } List <string> listOfEnumNames = propType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { prop.Enum.Add(GetEnumMemberValue(propType, enumName)); } } // Apply any options set in a [SwaggerWcfProperty] ApplyAttributeOptions(propertyInfo, prop); return(prop); }
private static Definition ConvertTypeToDefinition(Type definitionType, IList <string> hiddenTags, Stack <Type> typesStack) { DefinitionSchema schema = new DefinitionSchema(); //Get DataContractAttribute to set Schema name to match TypeFormat DataContractAttribute dca = definitionType.GetCustomAttribute <DataContractAttribute>(); //If DataContractAttribute.Name is set use that, otherwise use definitionType.Name if (dca != null) { if (!String.IsNullOrWhiteSpace(dca.Name)) { schema.Name = dca.Name; } else { schema.Name = definitionType.Name; } } ProcessTypeAttributes(definitionType, schema); // process schema.TypeFormat = Helpers.MapSwaggerType(definitionType, null); if (schema.TypeFormat.IsPrimitiveType) { return(null); } if (schema.TypeFormat.Type == ParameterType.String && schema.TypeFormat.Format == "enum") { schema.Enum = new List <string>(); Type propType = definitionType; if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable <>)) { propType = propType.GetEnumerableType(); } List <string> listOfEnumNames = propType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { schema.Enum.Add(GetEnumMemberValue(propType, enumName)); } } else if (schema.TypeFormat.Type == ParameterType.Array) { Type t = GetEnumerableType(definitionType); if (t != null) { schema.Ref = t.FullName; typesStack.Push(t); } } else { ProcessProperties(definitionType, schema, hiddenTags, typesStack); } return(new Definition { Schema = schema }); }
private static DefinitionProperty ProcessProperty(PropertyInfo propertyInfo, IList <string> hiddenTags, Stack <Type> typesStack) { if (propertyInfo.GetCustomAttribute <DataMemberAttribute>() == null || propertyInfo.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || propertyInfo.GetCustomAttributes <SwaggerWcfTagAttribute>() .Select(t => t.TagName) .Any(hiddenTags.Contains)) { return(null); } TypeFormat typeFormat = Helpers.MapSwaggerType(propertyInfo.PropertyType, null); DefinitionProperty prop = new DefinitionProperty { Title = propertyInfo.Name }; DataMemberAttribute dataMemberAttribute = propertyInfo.GetCustomAttribute <DataMemberAttribute>(); if (dataMemberAttribute != null) { if (!string.IsNullOrEmpty(dataMemberAttribute.Name)) { prop.Title = dataMemberAttribute.Name; } prop.Required = dataMemberAttribute.IsRequired; } DescriptionAttribute descriptionAttribute = propertyInfo.GetCustomAttribute <DescriptionAttribute>(); if (descriptionAttribute != null) { prop.Description = descriptionAttribute.Description; } prop.TypeFormat = typeFormat; if (prop.TypeFormat.Type == ParameterType.Object) { typesStack.Push(propertyInfo.PropertyType); prop.Ref = propertyInfo.PropertyType.FullName; return(prop); } if (prop.TypeFormat.Type == ParameterType.Array) { Type subType = propertyInfo.PropertyType.GetEnumerableType(); if (subType != null) { TypeFormat subTypeFormat = Helpers.MapSwaggerType(subType, null); if (subTypeFormat.Type == ParameterType.Object) { typesStack.Push(subType); } prop.Items = new ParameterItems { TypeFormat = subTypeFormat }; } } if (prop.TypeFormat.Type == ParameterType.String && prop.TypeFormat.Format == "enum") { prop.Enum = new List <string>(); List <string> listOfEnumNames = propertyInfo.PropertyType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { prop.Enum.Add(GetEnumMemberValue(propertyInfo.PropertyType, enumName)); } } return(prop); }
private static void ProcessProperties(Type definitionType, DefinitionSchema schema, IList <string> hiddenTags, Stack <Type> typesStack) { List <PropertyInfo> properties = new List <PropertyInfo>(); var type = definitionType; while (type != null) { var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var prop in props) { if (properties.Any(p => p.Name == prop.Name)) { continue; } properties.Add(prop); } type = type.BaseType; } //PropertyInfo[] properties = definitionType.GetProperties(BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic); schema.Properties = new List <DefinitionProperty>(); foreach (PropertyInfo propertyInfo in properties) { DefinitionProperty prop = ProcessProperty(propertyInfo, hiddenTags, typesStack); if (prop == null) { continue; } if (prop.TypeFormat.Type == ParameterType.Array) { Type propType = propertyInfo.PropertyType; Type t = propType.GetElementType() ?? GetEnumerableType(propType); if (t != null) { //prop.TypeFormat = new TypeFormat(prop.TypeFormat.Type, HttpUtility.HtmlEncode(t.FullName)); prop.TypeFormat = new TypeFormat(prop.TypeFormat.Type, null); TypeFormat st = Helpers.MapSwaggerType(t); if (st.Type == ParameterType.Array || st.Type == ParameterType.Object) { prop.Items.TypeFormat = new TypeFormat(ParameterType.Unknown, null); prop.Items.Ref = t.FullName; } else { prop.Items.TypeFormat = st; } } } if (prop.Required) { if (schema.Required == null) { schema.Required = new List <string>(); } schema.Required.Add(prop.Title); } schema.Properties.Add(prop); } }
internal IEnumerable <Tuple <string, PathAction> > GetActions(MethodInfo[] targetMethods, MethodInfo[] interfaceMethods, IList <Type> definitionsTypesList) { int methodsCounts = interfaceMethods.Count(); for (int index = 0; index < methodsCounts; index++) { MethodInfo implementation = targetMethods[index]; MethodInfo declaration = interfaceMethods[index]; //if the method is marked Hidden anywhere, skip it if (implementation.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || declaration.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null) { continue; } //if a tag from either implementation or declaration is marked as not visible, skip it List <SwaggerWcfTagAttribute> methodTags = implementation.GetCustomAttributes <SwaggerWcfTagAttribute>().ToList(); methodTags = methodTags.Concat(declaration.GetCustomAttributes <SwaggerWcfTagAttribute>()).ToList(); methodTags = methodTags.Distinct().ToList(); if (methodTags.Select(t => t.TagName).Any(HiddenTags.Contains)) { continue; } //find the WebGet/Invoke attributes, or skip if neither is present WebGetAttribute wg = declaration.GetCustomAttribute <WebGetAttribute>(); WebInvokeAttribute wi = declaration.GetCustomAttribute <WebInvokeAttribute>(); if (wg == null && wi == null) { continue; } string httpMethod = (wi == null) ? "GET" : wi.Method ?? "POST"; string uriTemplate = (wi == null) ? (wg.UriTemplate ?? "") : (wi.UriTemplate ?? ""); //implementation description overrides interface description string description = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "Description") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "Description") ?? Helpers.GetCustomAttributeValue <string, DescriptionAttribute>(implementation, "Description") ?? Helpers.GetCustomAttributeValue <string, DescriptionAttribute>(declaration, "Description") ?? ""; string summary = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "Summary") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "Summary") ?? ""; string operationId = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "OperationId") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "OperationId") ?? ""; if (operationId == "") { if (implementation.DeclaringType != null) { operationId = implementation.DeclaringType.FullName + "."; } operationId += implementation.Name; } string externalDocsDescription = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "ExternalDocsDescription") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "ExternalDocsDescription") ?? ""; string externalDocsUrl = Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(implementation, "ExternalDocsUrl") ?? Helpers.GetCustomAttributeValue <string, SwaggerWcfPathAttribute>(declaration, "ExternalDocsUrl") ?? ""; ExternalDocumentation externalDocs = null; if (!string.IsNullOrWhiteSpace(externalDocsDescription) || !string.IsNullOrWhiteSpace(externalDocsUrl)) { externalDocs = new ExternalDocumentation { Description = HttpUtility.HtmlEncode(externalDocsDescription), Url = HttpUtility.HtmlEncode(externalDocsUrl) }; } bool deprecated = Helpers.GetCustomAttributeValue <SwaggerWcfPathAttribute>(implementation, "Deprecated"); if (!deprecated) { deprecated = Helpers.GetCustomAttributeValue <SwaggerWcfPathAttribute>(declaration, "Deprecated"); } PathAction operation = new PathAction { Id = httpMethod.ToLowerInvariant(), Summary = HttpUtility.HtmlEncode(summary), Description = HttpUtility.HtmlEncode(description), Tags = methodTags.Where(t => !t.HideFromSpec).Select(t => HttpUtility.HtmlEncode(t.TagName)).ToList(), Consumes = new List <string>(GetConsumes(implementation, declaration)), Produces = new List <string>(GetProduces(implementation, declaration)), Deprecated = deprecated, OperationId = HttpUtility.HtmlEncode(operationId), ExternalDocs = externalDocs, Responses = GetResponseCodes(implementation, declaration, definitionsTypesList) // Schemes = TODO: how to get available schemes for this WCF service? (schemes: http/https) }; //try to map each implementation parameter to the uriTemplate. ParameterInfo[] parameters = declaration.GetParameters(); if (parameters.Any()) { operation.Parameters = new List <ParameterBase>(); } foreach (ParameterInfo parameter in parameters) { TypeFormat typeFormat = Helpers.MapSwaggerType(parameter.ParameterType, definitionsTypesList); SwaggerWcfParameterAttribute settings = implementation.GetParameters() .First(p => p.Position.Equals(parameter.Position)) .GetCustomAttribute <SwaggerWcfParameterAttribute>() ?? parameter.GetCustomAttribute <SwaggerWcfParameterAttribute>(); if (implementation.GetParameters() .First(p => p.Position.Equals(parameter.Position)) .GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null || parameter.GetCustomAttribute <SwaggerWcfHiddenAttribute>() != null) { continue; } List <SwaggerWcfTagAttribute> piTags = methodTags.Concat(parameter.GetCustomAttributes <SwaggerWcfTagAttribute>()) .ToList(); if (piTags.Select(t => t.TagName).Any(HiddenTags.Contains)) { continue; } operation.Parameters.Add(GetParameter(typeFormat, parameter, settings, uriTemplate, definitionsTypesList)); } if (!string.IsNullOrWhiteSpace(uriTemplate)) { int indexOfQuestionMark = uriTemplate.IndexOf('?'); if (indexOfQuestionMark >= 0) { uriTemplate = uriTemplate.Substring(0, indexOfQuestionMark); } } yield return(new Tuple <string, PathAction>(uriTemplate, operation)); } }
private static Definition ConvertTypeToDefinition(Type definitionType, IList <string> hiddenTags, Stack <Type> typesStack) { DefinitionSchema schema = new DefinitionSchema { Name = definitionType.GetModelName() }; ProcessTypeAttributes(definitionType, schema); // process schema.TypeFormat = Helpers.MapSwaggerType(definitionType, null); if (schema.TypeFormat.IsPrimitiveType) { return(null); } if (schema.TypeFormat.Type == ParameterType.Integer && schema.TypeFormat.Format == "enum") { schema.Enum = new List <int>(); Type propType = definitionType; if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable <>)) { propType = propType.GetEnumerableType(); } string enumDescription = ""; List <string> listOfEnumNames = propType.GetEnumNames().ToList(); foreach (string enumName in listOfEnumNames) { var enumMemberValue = DefinitionsBuilder.GetEnumMemberValue(propType, enumName); var enumMemberItem = Enum.Parse(propType, enumName, true); string enumMemberDescription = DefinitionsBuilder.GetEnumDescription((Enum)enumMemberItem); enumMemberDescription = (string.IsNullOrWhiteSpace(enumMemberDescription)) ? "" : $"({enumMemberDescription})"; if (schema.Description != null) { enumDescription += $"{Environment.NewLine}* `{enumMemberValue}` - {enumName} {enumMemberDescription}"; schema.Enum.Add(enumMemberValue); } } if (schema.Description != null && enumDescription != "") { schema.Description += $":{Environment.NewLine}{enumDescription}"; } } else if (schema.TypeFormat.Type == ParameterType.Array) { Type t = GetEnumerableType(definitionType); if (t != null) { schema.Ref = definitionType.GetModelName(); typesStack.Push(t); } } else { schema.Properties = new List <DefinitionProperty>(); TypePropertiesProcessor.ProcessProperties(definitionType, schema, hiddenTags, typesStack); TypeFieldsProcessor.ProcessFields(definitionType, schema, hiddenTags, typesStack); } return(new Definition { Schema = schema }); }