private ResourceListing getDocs(HttpActionContext actionContext) { var assemblyType = (actionContext.ActionDescriptor as ReflectedHttpActionDescriptor).MethodInfo.DeclaringType; var docProvider = new XmlCommentDocumentationProvider(); //(XmlCommentDocumentationProvider)GlobalConfiguration.Configuration.Services.GetDocumentationProvider(); ResourceListing r = SwaggerGen.CreateResourceListing(actionContext); foreach (var api in GlobalConfiguration.Configuration.Services.GetApiExplorer().ApiDescriptions) { if (api.ActionDescriptor.ActionName.EndsWith("API"))//Ignore each Default API action { continue; } string apiControllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName; if (api.Route.Defaults.ContainsKey(SwaggerGen.SWAGGER) || apiControllerName.ToUpper().Equals(SwaggerGen.SWAGGER.ToUpper())) { continue; } // Make sure we only report the current controller docs if (!apiControllerName.Equals(actionContext.ControllerContext.ControllerDescriptor.ControllerName)) { continue; } ResourceApi rApi = SwaggerGen.CreateResourceApi(api); r.apis.Add(rApi); ResourceApiOperation rApiOperation = SwaggerGen.CreateResourceApiOperation(r, api, docProvider); rApi.operations.Add(rApiOperation); foreach (var param in api.ParameterDescriptions) { ResourceApiOperationParameter parameter = SwaggerGen.CreateResourceApiOperationParameter(r, api, param, docProvider); rApiOperation.parameters.Add(parameter); } if (System.Configuration.ConfigurationManager.AppSettings["swagger:APITOKEN"] != null && System.Configuration.ConfigurationManager.AppSettings["swagger:APITOKEN"].Equals("true") && !api.ActionDescriptor.ActionName.EndsWith("API")) { //添加Token ResourceApiOperationParameter p = new ResourceApiOperationParameter(); p.name = "ApiToken"; p.description = "Api Token"; p.paramType = "path"; p.required = true; p.dataType = "String"; rApiOperation.parameters.Insert(0, p); } SwaggerGen.CreateModel(r, api, docProvider); //r.models = new ResourceApiModel(); } return(r); }
public static void CreateModel(ResourceListing r, ApiDescription api, XmlCommentDocumentationProvider docProvider) { if (r.models == null) { r.models = new ConcurrentDictionary <string, object>(); } ReflectedHttpActionDescriptor reflectedActionDescriptor = api.ActionDescriptor as ReflectedHttpActionDescriptor; if (reflectedActionDescriptor != null) { //this function will be called generating swagger API json //limitations //-only generating swagger models (API return type documentation) for return type is ApiResponse //--most calls fall into these 3 categories: //--ApiResponse<PageData<T>> //--ApiResponse<T> //--ApiResponse<T> where T is simple type such as object, string, int, etc. //-only generate detail when T is DataObject //implementation notes //-get the actual T //--when T is DataObject, add into a queue (i.e. a FIFO Stack) for next step processing //-loop until queue is empty //--process (add model details) for the first item in queue, remove it after processed //--during the processing, if found any property is type of DataObject, add the nested type into queue //-the reason to use a while loop with a queue is to avoid using recursive implementation which will throw a stack-overflow exception when it's too many nested types var returnType = reflectedActionDescriptor.MethodInfo.ReturnType; List <Type> queue = new List <Type>();//process queue AddTypeToProcessQueue(r, returnType, queue); //parameter handling var parameters = reflectedActionDescriptor.MethodInfo.GetParameters(); if (parameters != null && parameters.Length > 0) { foreach (var p in parameters) { if (p.ParameterType.IsGenericType) { var dataObjType = p.ParameterType.GetGenericArguments()[0]; AddTypeToProcessQueue(r, dataObjType, queue); } else { AddTypeToProcessQueue(r, p.ParameterType, queue); } } } if (returnType.IsGenericType) { Type[] types = returnType.GetGenericArguments(); if (types[0].Name.Equals("PageData`1")) { var dataObjType = types[0].GetGenericArguments()[0]; AddTypeToProcessQueue(r, dataObjType, queue); //ApiResponse_PageData_xxxxx var model = AddModelApiResponse(r, "ApiResponse_PageData_" + dataObjType.Name); if (model != null) { var p = new ResourceApiModelProperty(); p.type = "Array"; p.description = "Page data set"; var items = new Dictionary <string, string>(); items.Add("$ref", "PageData_" + dataObjType.Name); p.items = items; model.properties.Add("Results", p); } if (!r.models.ContainsKey("PageData_" + dataObjType.Name)) { model = new ResourceApiModel(); model.id = "PageData_" + dataObjType.Name; model.properties = new Dictionary <string, ResourceApiModelProperty>(); var p = new ResourceApiModelProperty(); p.type = "int"; p.description = "total no of qualified data"; model.properties.Add("TotalRecords", p); p = new ResourceApiModelProperty(); p.type = "bool"; p.description = "whether has next page"; model.properties.Add("HasNextPage", p); p = new ResourceApiModelProperty(); p.type = "int"; p.description = "curent page index, start from 0"; model.properties.Add("PageIndex", p); p = new ResourceApiModelProperty(); p.type = "int"; p.description = "how many records in one page"; model.properties.Add("PageSize", p); p = new ResourceApiModelProperty(); p.type = "Array"; p.description = "A page of data"; var items = new Dictionary <string, string>(); items.Add("$ref", dataObjType.Name); p.items = items; model.properties.Add("Results", p); r.models.TryAdd("PageData_" + dataObjType.Name, model); } } else if (returnType.Name.Equals("Page`1")) { var dataObjType = types[0]; AddTypeToProcessQueue(r, dataObjType, queue); var paging = returnType.GetProperty("Paging"); if (paging != null) {//add paging type manually AddTypeToProcessQueue(r, paging.PropertyType, queue); } //Page_xxxxx if (!r.models.ContainsKey("Page_" + dataObjType.Name)) { var model = new ResourceApiModel(); model.id = "Page_" + dataObjType.Name; model.properties = new Dictionary <string, ResourceApiModelProperty>(); var p = new ResourceApiModelProperty(); p.type = "Paging"; p.description = "Paging info"; model.properties.Add("Paging", p); p = new ResourceApiModelProperty(); p.type = "Array"; p.description = "A page of data"; var items = new Dictionary <string, string>(); items.Add("$ref", dataObjType.Name); p.items = items; model.properties.Add("Records", p); r.models.TryAdd("Page_" + dataObjType.Name, model); } } else { var dataObjType = types[0]; AddTypeToProcessQueue(r, dataObjType, queue); } } //process queue while (queue.Count > 0) { var type = queue[0]; AddModelDataObject(r, queue[0], queue); queue.Remove(type); } } }
/// <summary> /// Creates an operation parameter /// </summary> /// <param name="api">Description of the api via the ApiExplorer</param> /// <param name="param">Description of a parameter on an operation via the ApiExplorer</param> /// <param name="docProvider">Access to the XML docs written in code</param> /// <returns>An operation parameter</returns> public static ResourceApiOperationParameter CreateResourceApiOperationParameter(ResourceListing r, ApiDescription api, ApiParameterDescription param, XmlCommentDocumentationProvider docProvider) { string paramType = (param.Source.ToString().Equals(FROMURI)) ? QUERY : BODY; var dataType = param.ParameterDescriptor.ParameterType.Name; switch (dataType) { case "List`1": var dataObjType = param.ParameterDescriptor.ParameterType.GetGenericArguments()[0]; dataType = string.Format("Array[{0}]", dataObjType.Name); break; case "Nullable`1": var dd = param.ParameterDescriptor.ParameterType.GetGenericArguments()[0]; dataType = dd.Name; break; case "Dictionary`2": dataType = string.Format("Array[{0},{1}]", param.ParameterDescriptor.ParameterType.GetGenericArguments()[0].Name, param.ParameterDescriptor.ParameterType.GetGenericArguments()[1].Name); break; default: if (!IsExceptType(param.ParameterDescriptor.ParameterType)) { AddModelDataObject(r, param.ParameterDescriptor.ParameterType); } break; } ResourceApiOperationParameter parameter = new ResourceApiOperationParameter() { paramType = (paramType == "query" && api.RelativePath.IndexOf("{" + param.Name + "}") > -1) ? PATH : paramType, name = param.Name, description = param.Name.Equals("sessionKey") ? "Login session" : (string.IsNullOrWhiteSpace(param.Documentation) ? NODESCRIPTION : param.Documentation), dataType = dataType, required = docProvider.GetRequired(param.ParameterDescriptor) }; return(parameter); }
/// <summary> /// Creates an api operation /// </summary> /// <param name="api">Description of the api via the ApiExplorer</param> /// <param name="docProvider">Access to the XML docs written in code</param> /// <returns>An api operation</returns> public static ResourceApiOperation CreateResourceApiOperation(ResourceListing r, ApiDescription api, XmlCommentDocumentationProvider docProvider) { ResourceApiOperation rApiOperation = new ResourceApiOperation() { httpMethod = api.HttpMethod.ToString(), nickname = docProvider.GetNickname(api.ActionDescriptor), responseClass = docProvider.GetResponseClass(api.ActionDescriptor), summary = docProvider.GetDocumentation(api.ActionDescriptor), notes = docProvider.GetNotes(api.ActionDescriptor), parameters = new List <ResourceApiOperationParameter>(), }; if (string.IsNullOrEmpty(rApiOperation.notes) || rApiOperation.notes.Equals("No Documentation Found.")) { rApiOperation.notes = rApiOperation.summary; } return(rApiOperation); }