private Content(TypeDefinition type, Documentation documentation) { this.Add("swagger: '2.0'"); this.Add("info:"); using (new Block(this)) { this.Add("title: ", type.Name); if (documentation[type] != null) { this.Add("description: ", documentation[type]); } var _customAttribute = type.Module.Assembly.GetCustomAttribute <AssemblyFileVersionAttribute>(); var _argument = _customAttribute?.Argument <string>(0); if (_argument != null) { this.Add($"version: \"{ _argument }\""); } } this.Add("host: localhost"); this.Add("schemes:"); using (new Block(this)) { this.Add("- http"); this.Add("- https"); } this.Add("basePath: /", type.Name); this.Add("paths:"); var _methods = type.Methods.Where(_Method => _Method.IsPublic && !_Method.IsStatic && _Method.GetCustomAttribute <OperationContractAttribute>() != null).OrderBy(_Method => _Method.MetadataToken.ToInt32()).ToArray(); using (new Block(this)) { foreach (var _method in _methods) { this.Add(_method, documentation); } } this.Add("definitions:"); using (new Block(this)) { var responses = _methods.Select(_Method => _Method.ReturnType).Distinct() .OrderBy(typeRef => typeRef.Name) .Where(typeRef => !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(void)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(bool)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(string)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(int)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(long)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(DateTime)).Resolve())) .Select(_Type => _Type.IsArray ? _Type.GetElementType() : _Type).Distinct(); foreach (var response in responses) { if (!definitionList.Contains(response)) { definitionList.Add(response); } } var resparameters = _methods.SelectMany(_Method => _Method.Parameters).Select(x => x.ParameterType) .OrderBy(typeRef => typeRef.Name) .Where(typeRef => !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(void)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(bool)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(string)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(int)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(long)).Resolve()) && !(typeRef.Resolve() == typeRef.Resolve().Module.ImportReference(typeof(DateTime)).Resolve())) .Select(_Type => _Type.IsArray ? _Type.GetElementType() : _Type).Distinct(); foreach (var resparameter in resparameters) { if (!definitionList.Contains(resparameter)) { definitionList.Add(resparameter); } } int beforeCnt = definitionList.Count; for (int i = 0; i < beforeCnt; i++) { ParseComplexType(definitionList[i], documentation); } int afterCnt = definitionList.Count; for (int i = beforeCnt; i < afterCnt; i++) { ParseComplexType(definitionList[i], documentation); } int afterafterCnt = definitionList.Count; for (int i = afterCnt; i < afterafterCnt; i++) { ParseComplexType(definitionList[i], documentation); } } }
static public Document Generate(TypeDefinition type, Documentation documentation) { return(Content.Generate(type, documentation ?? Documentation.Empty())); }
static public Document Generate(TypeDefinition type, Documentation documentation) { return(new Document(type, new Content(type, documentation))); }
private void Add(MethodDefinition method, ParameterDefinition parameter, Documentation documentation) { var _type = parameter.ParameterType; this.Add("- name: ", parameter.Name); using (new Block(this)) { if (_type.Resolve() == _type.Module.ImportReference(typeof(string)).Resolve() || _type.Resolve() == _type.Module.ImportReference(typeof(int)).Resolve() || _type.Resolve() == _type.Module.ImportReference(typeof(long)).Resolve() || _type.Resolve() == _type.Module.ImportReference(typeof(DateTime)).Resolve() || _type.IsArray) { this.Add("in: query"); if (documentation != null && documentation[method, parameter] != null) { this.Add("description: ", documentation[method, parameter]); } this.Add("required: ", parameter.ParameterType.IsValueType.ToString().ToLower()); this.Add(parameter.ParameterType, documentation); } else { this.Add("in: body"); if (documentation != null && documentation[method, parameter] != null) { this.Add("description: ", documentation[method, parameter]); } this.Add("required: ", parameter.ParameterType.IsValueType.ToString().ToLower()); this.Add("schema:"); using (new Block(this)) { this.Add(parameter.ParameterType, documentation); } } } }
private void Add(MethodDefinition method, Documentation documentation) { var _parameters = method.Parameters; this.Add("/", method.Name, ":"); using (new Block(this)) { var _attribute = method.GetCustomAttribute <WebInvokeAttribute>(); if (_attribute == null) { _attribute = method.GetCustomAttribute <WebGetAttribute>(); if (_attribute == null) { return; } this.Add("get:"); } else if (string.IsNullOrEmpty(_attribute.Value <string>("Method"))) { return; } else { this.Add(_attribute.Value <string>("Method").ToLower(), ":"); } using (new Block(this)) { this.Add("summary: ", method.Name); if (documentation != null && documentation[method].Summary != null) { this.Add("description: ", documentation[method].Summary); } this.Add("consumes:"); using (new Block(this)) { if (_attribute.Value("RequestFormat") && _attribute.Value <WebMessageFormat>("RequestFormat") == WebMessageFormat.Json) { this.Add("- application/json"); } else { this.Add("- application/xml"); } } this.Add("produces:"); using (new Block(this)) { if (_attribute.Value("ResponseFormat") && _attribute.Value <WebMessageFormat>("ResponseFormat") == WebMessageFormat.Json) { this.Add("- application/json"); } else { this.Add("- application/xml"); } } if (_parameters.Count > 0) { this.Add("parameters:"); using (new Block(this)) { foreach (var _parameter in _parameters) { this.Add(method, _parameter, documentation); } } this.Add("tags:"); using (new Block(this)) { this.Add("- ", method.DeclaringType.Name); } } this.Add("responses:"); using (new Block(this)) { this.Add("200:"); using (new Block(this)) { if (documentation != null && documentation[method].Response != null) { this.Add("description: ", documentation[method].Response); } else { this.Add("description: OK"); } if (method.ReturnType.Resolve() != method.Module.ImportReference(typeof(void)).Resolve()) { this.Add("schema:"); using (new Block(this)) { this.Add(method.ReturnType, documentation); } } } this.Add("default:"); using (new Block(this)) { this.Add("description: failed"); this.Add("schema:"); using (new Block(this)) { this.Add("type: \"string\""); } } } } } }
static public IEnumerable <YAML.Document> Generate(AssemblyDefinition assembly, Documentation documentation) { foreach (var _type in assembly.MainModule.Types.Where(_Type => _Type.IsInterface && _Type.GetCustomAttribute <ServiceContractAttribute>() != null)) { yield return(Document.Generate(_type, documentation)); } }
private Content(TypeDefinition type, Documentation documentation) { this.Add("swagger: '2.0'"); this.Add("info:"); using (new Block(this)) { this.Add("title: ", type.Name); if (documentation[type] != null) { this.Add("description: ", documentation[type]); } this.Add($"version: \"{ type.Module.Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Argument<string>(0) }\""); } this.Add("host: localhost"); this.Add("schemes:"); using (new Block(this)) { this.Add("- http"); this.Add("- https"); } this.Add("basePath: /", type.Name); //this.Add("consumes:"); //using (new Block(this)) { this.Add("- application/json"); } //this.Add("produces:"); //using (new Block(this)) { this.Add("- application/json"); } this.Add("paths:"); var _methods = type.Methods.Where(_Method => _Method.IsPublic && !_Method.IsStatic && _Method.GetCustomAttribute <OperationContractAttribute>() != null).OrderBy(_Method => _Method.MetadataToken.ToInt32()).ToArray(); using (new Block(this)) { foreach (var _method in _methods) { this.Add(_method, documentation); } } this.Add("definitions:"); using (new Block(this)) { foreach (var _response in _methods.Select(_Method => _Method.ReturnType).Distinct().OrderBy(_Type => _Type.Name).Where(_Type => !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(void)).Resolve()) && !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(bool)).Resolve()) && !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(string)).Resolve()) && !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(int)).Resolve()) && !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(long)).Resolve()) && !(_Type.Resolve() == _Type.Resolve().Module.Import(typeof(DateTime)).Resolve())).Select(_Type => _Type.IsArray ? _Type.GetElementType() : _Type).Distinct()) { if (_response.Resolve() == _response.Module.Import(typeof(void)).Resolve()) { throw new NotSupportedException("Type 'System.Void' is not supported as return type."); } if (_response.Resolve().GetCustomAttribute <DataContractAttribute>() == null) { throw new NotSupportedException(string.Format("Type '{0}' is not a data contract.", _response.FullName)); } this.Add(_response.Name, ":"); using (new Block(this)) { this.Add("type: object"); if (documentation != null && documentation[_response.Resolve()] != null) { this.Add(string.Concat("description: ", documentation[_response.Resolve()])); } this.Add("properties:"); using (new Block(this)) { foreach (var _property in _response.Resolve().Properties.Where(_Property => _Property.GetCustomAttribute <DataMemberAttribute>() != null).OrderBy(_Property => _Property.MetadataToken.ToInt32())) { this.Add(_property, documentation); } } } } //this.Add("Error:"); //using (new Block(this)) //{ // this.Add("type: object"); // this.Add("properties:"); // using (new Block(this)) // { // this.Add("Code:"); // using (new Block(this)) // { // this.Add("type: string"); // this.Add("description: Code"); // } // this.Add("Message:"); // using (new Block(this)) // { // this.Add("type: string"); // this.Add("description: Message"); // } // } //} } }
private void Add(MethodDefinition method, Documentation documentation) { var _parameters = method.Parameters; this.Add("/", method.Name, ":"); using (new Block(this)) { var _attribute = method.GetCustomAttribute <WebInvokeAttribute>(); if (_attribute == null) { _attribute = method.GetCustomAttribute <WebGetAttribute>(); if (_attribute == null) { throw new NotSupportedException(); } this.Add("get:"); } else if (string.IsNullOrEmpty(_attribute.Value <string>("Method"))) { throw new NotSupportedException(); } else { this.Add(_attribute.Value <string>("Method").ToLower(), ":"); } using (new Block(this)) { this.Add("summary: ", method.Name); if (documentation != null && documentation[method].Summary != null) { this.Add("description: ", documentation[method].Summary); } this.Add("consumes:"); using (new Block(this)) { if (_attribute.Value("RequestFormat") && _attribute.Value <WebMessageFormat>("RequestFormat") == WebMessageFormat.Json) { this.Add("- application/json"); } else { this.Add("- application/xml"); } } this.Add("produces:"); using (new Block(this)) { if (_attribute.Value("ResponseFormat") && _attribute.Value <WebMessageFormat>("ResponseFormat") == WebMessageFormat.Json) { this.Add("- application/json"); } else { this.Add("- application/xml"); } } if (_parameters.Count > 0) { this.Add("parameters:"); using (new Block(this)) { foreach (var _parameter in _parameters) { this.Add(method, _parameter, documentation); } } this.Add("tags:"); using (new Block(this)) { this.Add("- ", method.DeclaringType.Name); } } this.Add("responses:"); using (new Block(this)) { this.Add("200:"); using (new Block(this)) { if (documentation != null && documentation[method].Response != null) { this.Add("description: ", documentation[method].Response); } else { this.Add("description: OK"); } if (method.ReturnType.Resolve() != method.Module.Import(typeof(void)).Resolve()) { this.Add("schema:"); using (new Block(this)) { this.Add(method.ReturnType); } } } //this.Add("400:"); //using (new Block(this)) //{ // this.Add("description: Bad Request"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} //this.Add("401:"); //using (new Block(this)) //{ // this.Add("description: Unauthorized"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} //this.Add("403:"); //using (new Block(this)) //{ // this.Add("description: Forbidden"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} //this.Add("409:"); //using (new Block(this)) //{ // this.Add("description: Conflict"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} //this.Add("500:"); //using (new Block(this)) //{ // this.Add("description: Internal Server Error"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} //this.Add("503:"); //using (new Block(this)) //{ // this.Add("description: Service Unavailable"); // this.Add("schema:"); // using (new Block(this)) { this.Add("type: \"string\""); } //} this.Add("default:"); using (new Block(this)) { this.Add("description: failed"); this.Add("schema:"); using (new Block(this)) { this.Add("type: \"string\""); } } } } } }
private Documentation(string location) { foreach (var _member in XDocument.Load(location).Descendants("member")) { var _name = _member.Attribute("name").Value; this.m_Dictionary.Add(_name, Documentation.Arrange(_member.Element("summary").Value)); if (_name.StartsWith("M:")) { this.m_Dictionary.Add(string.Concat("R", _name.Substring(1)), Documentation.Arrange(_member.Element("returns").Value)); foreach (var _parameter in _member.Elements("param")) { this.m_Dictionary.Add(string.Concat("A", _name.Substring(1), ".", _parameter.Attribute("name").Value), Documentation.Arrange(_parameter.Value)); } } } }