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)); } }
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)); } }