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 ParameterBase GetParameter(TypeFormat typeFormat, ParameterInfo parameter, SwaggerWcfParameterAttribute settings, string uriTemplate, IList <Type> definitionsTypesList) { string description = settings != null ? settings.Description : null; bool required = settings != null && settings.Required; string name = parameter.Name; //Check for set DataContractAttribute to set Name and - Should this check for, and set DataContractAttribute.Namespace as well? /GustafRG //DataContractAttribute was not accessible on parameter, but on parameter.ParameterType. /GustafRG DataContractAttribute dataContractAttribute = parameter.ParameterType.GetCustomAttribute <DataContractAttribute>(); if (dataContractAttribute != null) { if (!string.IsNullOrEmpty(dataContractAttribute.Name)) { name = dataContractAttribute.Name; } else { name = parameter.ParameterType.Name; } } //Removed this. DataMemberAttribute is not valid on Object, Only on Object Members. Also, it does not seem to be accessible on "parameter" /GustafRG //DataMemberAttribute dataMemberAttribute = parameter.ParameterType.GetCustomAttribute<DataMemberAttribute>(); // if (dataMemberAttribute != null && !string.IsNullOrEmpty(dataMemberAttribute.Name)) // name = dataMemberAttribute.Name; InType inType = GetInType(uriTemplate, parameter.Name); if (inType == InType.Path) { required = true; } if (!required && !parameter.HasDefaultValue) { required = true; } Type paramType = parameter.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); ParameterPrimitive arrayParam = new ParameterPrimitive { Name = name, Description = description, In = inType, Required = required, TypeFormat = typeFormat, Items = new ParameterItems { Items = new ParameterSchema { SchemaRef = t.FullName } }, 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); } //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.FullName)); 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); }
private ParameterBase GetParameter(TypeFormat typeFormat, ParameterInfo parameter, SwaggerWcfParameterAttribute settings, string uriTemplate, IList <Type> definitionsTypesList) { string description = settings != null ? settings.Description : null; bool required = settings != null && settings.Required; string name = parameter.Name; DataMemberAttribute dataMemberAttribute = parameter.GetCustomAttribute <DataMemberAttribute>(); if (dataMemberAttribute != null && !string.IsNullOrEmpty(dataMemberAttribute.Name)) { name = dataMemberAttribute.Name; } InType inType = GetInType(uriTemplate, 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); ParameterPrimitive arrayParam = new ParameterPrimitive { Name = name, Description = description, In = inType, Required = required, TypeFormat = typeFormat, Items = new ParameterItems { Items = new ParameterSchema { SchemaRef = t.FullName } }, 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) { 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.FullName)); 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.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)); } }