private static XmlDocument LoadDocumentation(Dictionary <string, XmlDocument> xmldocs, string path, string assembly) { #region Validations if (xmldocs == null) { throw new ArgumentNullException(nameof(xmldocs)); } if (path == null) { throw new ArgumentNullException(nameof(path)); } if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } #endregion /* * */ if (xmldocs.ContainsKey(assembly) == true) { return(xmldocs[assembly]); } /* * */ string file = Path.Combine(path, assembly + ".xml"); if (File.Exists(file) == false) { Konsole.Debug("miss: '{0}'", file); xmldocs.Add(assembly, null); return(null); } /* * */ Konsole.Debug("xmld: '{0}'", file); XmlDocument doc = new XmlDocument(); doc.Load(file); xmldocs.Add(assembly, doc); return(doc); }
static int Main(string[] args) { var cl = CommandLine.Parse(args); if (cl == null) { return(-1); } /* * */ string assemblyPath = Path.Combine(Environment.CurrentDirectory, cl.Assembly); if (File.Exists(assemblyPath) == false) { Konsole.Fatal("ERR: File '{0}' not found.", cl.Assembly); return(1); } /* * */ AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += new ResolveEventHandler((sender, eventArgs) => { string folderPath = Path.GetDirectoryName(assemblyPath); string depPath = Path.Combine(folderPath, new AssemblyName(eventArgs.Name).Name + ".dll"); if (File.Exists(depPath) == false) { return(null); } Konsole.Debug("need: '{0}'", depPath); return(Assembly.LoadFrom(depPath)); }); /* * */ Konsole.Debug("load: '{0}'", assemblyPath); Assembly assembly; try { assembly = Assembly.LoadFile(assemblyPath); } catch (FileLoadException ex) { Konsole.Fatal(ex, "ERR: Could not load assembly '{0}'.", assemblyPath); return(2); } catch (BadImageFormatException ex) { Konsole.Fatal(ex, "ERR: Could not load assembly '{0}'.", assemblyPath); return(3); } /* * */ XmlDocument doc = new XmlDocument(); var module = doc .AddElement("module") .AddAttribute("name", cl.Application); /* * */ var controllers = assembly.GetExportedTypes().Where(type => typeof(ApiController).IsAssignableFrom(type)); List <Type> types = new List <Type>(); foreach (var c in controllers) { var service = module .AddElement("service") .AddAttribute("name", c.Name.Substring(0, c.Name.Length - "Controller".Length)) .AddAttribute("ref", ToReference(c)); foreach (var m in c.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var post = m.GetCustomAttribute <HttpPostAttribute>(); if (post == null) { continue; } var method = service .AddElement("method") .AddAttribute("name", m.Name); Type requestType = m.GetParameters()[0].ParameterType; Type responseType = m.ReturnType.GetGenericArguments()[0]; var request = method.AddElement("request").AddAttribute("ref", ToReference(requestType)); EmitTypeDefinition(request, requestType); WalkTypes(types, requestType); var response = method.AddElement("response").AddAttribute("ref", ToReference(responseType)); EmitTypeDefinition(response, responseType); WalkTypes(types, responseType); } } /* * Emit all of the used types. */ var typesDef = module.AddElement("types"); foreach (var t in types) { var xml = t.GetCustomAttribute <XmlTypeAttribute>(); if (xml == null) { Console.WriteLine("warn: type '{0}' does not have XmlType attribute.", t.FullName); } if (t.IsEnum == true) { var enumDef = typesDef.AddElement("enumeration") .AddAttribute("name", t.Name) .AddAttribute("ref", ToReference(t)); if (xml != null) { enumDef.AddAttribute("ns", xml.Namespace); } foreach (string n in t.GetEnumNames()) { enumDef.AddElement("enum").AddAttribute("value", n); } } else { var typeDef = typesDef.AddElement("type") .AddAttribute("name", t.Name) .AddAttribute("ref", ToReference(t)); if (xml != null) { typeDef.AddAttribute("ns", xml.Namespace); } EmitTypeDefinition(typeDef, t); } } /* * Add documentation */ Dictionary <string, XmlDocument> xmldocs = new Dictionary <string, XmlDocument>(); foreach (XmlElement elem in doc.SelectNodes(" //*[ @ref ] ")) { string[] tref = elem.Attributes["ref"].Value.Split(','); XmlDocument xmldoc = LoadDocumentation(xmldocs, Path.GetDirectoryName(assemblyPath), tref[1]); if (xmldoc == null) { continue; } if (elem.LocalName == "service") { foreach (XmlElement method in elem.SelectNodes(" method ")) { var memberName = "M:" + tref[0] + "." + method.Attributes["name"].Value; var summaryNode = xmldoc.SelectSingleNode($" /doc/members/member[ starts-with( @name, '{ memberName }' ) ]/summary "); if (summaryNode != null) { string summary = summaryNode.InnerText.Trim(); if (summary.Length > 0) { method.AddElement("summary").InnerText = summary; } } } } if (elem.LocalName == "request" || elem.LocalName == "response" || elem.LocalName == "type") { foreach (XmlElement property in elem.SelectNodes(" p ")) { string memberName = "P:" + tref[0] + "." + property.Attributes["name"].Value; var summaryNode = xmldoc.SelectSingleNode($" /doc/members/member[ starts-with( @name, '{ memberName }' ) ]/summary "); if (summaryNode != null) { string summary = summaryNode.InnerText.Trim(); if (summary.Length > 0) { property.AddElement("summary").InnerText = summary; } } } } } // doc.Save( Console.Out ); /* * */ XslCompiledTransform xslt = new XslCompiledTransform(); using (StringReader sr = new StringReader(Resources.ToClient)) { using (XmlReader xr = XmlReader.Create(sr)) { xslt.Load(xr); } } /* * */ string output = Path.Combine(Environment.CurrentDirectory, cl.Output); Konsole.Info("Generating {0}...", output); using (TextWriter xw = new StreamWriter(output, false, Encoding.UTF8)) { XsltArgumentList xargs = new XsltArgumentList(); xargs.AddParam("Namespace", "", cl.Namespace); xargs.AddParam("Async", "", cl.Async); xargs.AddParam("Sync", "", cl.Sync); xargs.AddExtensionObject("urn:eo-util", new XsltExtensionObject()); try { xslt.Transform(doc, xargs, xw); } catch (Exception ex) { Konsole.Fatal(ex); } } return(0); }