private static void AddModelDataObject(ResourceListing r, Type type, List <Type> queue) { if (!r.models.ContainsKey(type.Name)) { var model = new ResourceApiModel(); model.id = type.Name; model.properties = new Dictionary <string, ResourceApiModelProperty>(); foreach (var pi in type.GetProperties()) { var ignore = pi.GetCustomAttribute <System.Runtime.Serialization.IgnoreDataMemberAttribute>(); if (ignore != null) { continue; } var p = new ResourceApiModelProperty(); switch (pi.PropertyType.Name) { case "List`1": var dataObjType = pi.PropertyType.GetGenericArguments()[0]; AddTypeToProcessQueue(r, dataObjType, queue); p.type = "Array"; var items = new Dictionary <string, string>(); items.Add("$ref", dataObjType.Name); p.items = items; break; case "Nullable`1": var dd = pi.PropertyType.GetGenericArguments()[0]; p.type = dd.Name; AddTypeToProcessQueue(r, dd, queue); break; case "Dictionary`2": p.type = string.Format("Array[{0},{1}]" , pi.PropertyType.GetGenericArguments()[0].Name , pi.PropertyType.GetGenericArguments()[1].Name); break; default: p.type = pi.PropertyType.Name; AddTypeToProcessQueue(r, pi.PropertyType, queue); break; } //get description from xml p.description = GetDocumentation(pi); if (string.IsNullOrWhiteSpace(p.description)) { p.description = NODESCRIPTION; } if (!model.properties.ContainsKey(pi.Name)) { model.properties.Add(pi.Name, p); } //check if this is a nested data obj type, put into queue if yes } r.models.TryAdd(type.Name, model); } }
private static ResourceApiModel AddModelApiResponse(ResourceListing r, string targetTypeName) { if (!r.models.ContainsKey(targetTypeName)) { var model = new ResourceApiModel(); model.id = targetTypeName; model.properties = new Dictionary <string, ResourceApiModelProperty>(); var p = new ResourceApiModelProperty(); p.type = "bool"; p.description = "Indicates whether the API call is success or not"; model.properties.Add("Success", p); p = new ResourceApiModelProperty(); p.type = "string"; p.description = "Additional message for API result"; model.properties.Add("Message", p); p = new ResourceApiModelProperty(); p.type = "Exception"; p.description = "In case catch an exception"; model.properties.Add("Exception", p); r.models.TryAdd(targetTypeName, model); return(model); } else { return(null); } }
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); } } }