private Type GetObjectType(Type[] types, Example example) { Type matchingType = null; if (types != null) { if (types.Length == 1) { matchingType = types[0]; } else { if (example.MimeType != null) { foreach (Type type in types) { if (type.GetCustomAttributes <ContentTypeAttribute>().Any(a => a.ContentType.Equals(example.MimeType))) { matchingType = type; break; } } } if (matchingType == null) { SerialisationLog.Warning(string.Concat("There are multiple request or response types for ", example.ClassName, ".", example.MethodName, " ", example.ExampleType, " but no mimetype specified in the example tag in ", example.DocFilename)); } } } return(matchingType); }
private static string FindAssemblyPath() { string path = null; string binDir = string.Concat(GetRootDirectory(), "/src/", WEBSERVICE_NAME, "/bin"); string[] filenames = null; Console.WriteLine(string.Concat("Searching for DeviceServer assemblies in ", binDir, "...")); try { filenames = Directory.GetFiles(binDir, string.Concat("*", WEBSERVICE_NAME, ".exe"), SearchOption.AllDirectories); } catch (DirectoryNotFoundException) { SerialisationLog.Error("Could not find bin directory - has the Device Server been built?"); } if (filenames != null) { List <FileInfo> files = filenames.Select(f => new FileInfo(f)) .Where(f => f.Directory.GetDirectories().Length == 0) // must be bottom level directory to include all dependencies .OrderBy(f => f.LastWriteTime) // select the latest built configuration .ToList(); Console.WriteLine(string.Concat("Found ", files.Count, " assemblies:")); foreach (FileInfo fileInfo in files) { Console.WriteLine(string.Concat("*", fileInfo.FullName.Substring(binDir.Length))); } if (files.Count > 0) { path = files.Last().FullName; Console.WriteLine("Latest assembly: " + path.Substring(binDir.Length)); } } return(path); }
public static void Main(string[] args) { if (args.Length == 0 || args.Any(a => a.Equals("-h") || a.Equals("--help"))) { WriteHelp(); } else { string path = null; for (int i = 0; i < args.Length - 1; i++) { bool argument = true; if (args[i].Equals("-p") || args[i].Equals("--path")) { path = args[i + 1]; } else if (args[i].Equals("-r") || args[i].Equals("--ramlVersion")) { DocumentationSerialiserFactory.RAMLVersion = args[i + 1]; } else { argument = false; } if (argument) { List <string> temp = args.ToList(); temp.RemoveRange(i, 2); args = temp.ToArray(); i--; } } if (path == null) { path = FindAssemblyPath(); } if (string.IsNullOrEmpty(path)) { Console.WriteLine("Could not find Device Server Executable. "); Console.Out.Flush(); } else { Assembly assembly = null; try { assembly = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path)); } catch (Exception exception) { SerialisationLog.Error(string.Concat("Failed to load assembly at ", path, ": ", exception)); } if (assembly != null) { ResourceNode resourceTree = null; try { Console.WriteLine("Gathering resources from assembly..."); resourceTree = AssemblyReader.ReadAssembly(assembly); } catch (Exception exception) { SerialisationLog.Error(string.Concat("Failed to generate resource tree from assembly at ", path, ": ", exception)); } if (resourceTree != null) { IConfigurationBuilder builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables(); //.AddCommandLine(args); IConfigurationRoot root = builder.Build(); DocumentationHeaderSettings headerSettings = new DocumentationHeaderSettings(); root.GetSection("HeaderSettings").Bind(headerSettings); SchemaStore schemaStore = new SchemaStore(resourceTree); ExampleStore exampleStore = new ExampleStore(string.Concat(GetRootDirectory(), "/doc/"), resourceTree); args = args.Where(a => !a.StartsWith("-")).ToArray(); // remove options int numSuccess = 0; for (int i = 0; i < args.Length; i++) { try { Console.WriteLine(string.Concat("Generating documentation file: ", args[i])); GenerateDocumentation(resourceTree, headerSettings, schemaStore, exampleStore, args[i]); numSuccess++; } catch (Exception exception) { SerialisationLog.Error(string.Concat("Failed to generate documentation for ", args[i], ": ", exception)); } } Console.WriteLine(string.Concat(numSuccess, "/", args.Length, " documentation files generated successfully.")); Console.WriteLine(string.Concat(SerialisationLog.Errors, " errors, ", SerialisationLog.Warnings, " warnings.")); } } } } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); }
public void ReadExamples(string baseDirectory, string filename, ResourceNode resourceTree) { Example currentExample = null; StringBuilder currentExampleBody = null; TDataExchangeFormat currentExampleFormat = TDataExchangeFormat.None; bool inExample = false; string lastHeading = null; bool generateXml = true; foreach (string line in File.ReadLines(filename)) { string trimmed = line.Trim(); if (trimmed.StartsWith("#")) { lastHeading = trimmed.Replace("#", "").Trim().Replace(" ", "-").ToLower(); } else if (trimmed.StartsWith("[]: [!generateXml]")) { generateXml = false; } if (trimmed.StartsWith("```")) { if (currentExample != null) { string exampleFormat = trimmed.Substring("```".Length); if (exampleFormat.Equals(TDataExchangeFormat.Json.ToString().ToLower())) { currentExampleFormat = TDataExchangeFormat.Json; inExample = true; } else if (exampleFormat.Equals(FORM_EXAMPLE)) { currentExampleFormat = TDataExchangeFormat.FormUrlEncoded; inExample = true; } else if (inExample && exampleFormat.Length == 0) { if (currentExampleFormat == TDataExchangeFormat.FormUrlEncoded) { currentExample.Content.Add(currentExampleFormat, currentExampleBody.ToString()); } else { currentExample.Content.Add(TDataExchangeFormat.Json, currentExampleBody.ToString()); if (generateXml) { currentExample.Content.Add(TDataExchangeFormat.Xml, JsonToXml(currentExample, resourceTree, currentExampleBody.ToString())); } } currentExample = null; inExample = false; generateXml = true; } } } else { if (inExample) { if (line.Trim().Length > 0) { currentExampleBody.Append(line);// string.Concat(line, "\r\n")); } } else { MatchCollection matches = EXAMPLE_NAME_REGEX.Matches(trimmed); if (matches.Count == 1) { string fullExampleName = matches[0].Value; string prefix = "[]: ["; string suffix = "]"; string withoutSquareBrackets = fullExampleName.Substring(prefix.Length, matches[0].Value.Length - prefix.Length - suffix.Length); string[] parts = withoutSquareBrackets.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); string className = parts[0]; string methodName = parts[1]; string mimeType = trimmed.Substring(fullExampleName.Length); if (mimeType.Length > 0) { if (mimeType.StartsWith("[") && mimeType.EndsWith("]")) { mimeType = mimeType.Substring(1, mimeType.Length - 2); } else { SerialisationLog.Warning(string.Concat("Invalid mimetype on example tag: ", trimmed, " in ", filename)); mimeType = ""; } } if (resourceTree.Find(className, methodName) != null) { TMessageType messageType = (TMessageType)Enum.Parse(typeof(TMessageType), parts[2]); string exampleFilename = filename.Substring(baseDirectory.Length); currentExample = new Example(exampleFilename, lastHeading, className, methodName, messageType, mimeType); currentExampleBody = new StringBuilder(); string key = string.Concat(currentExample.ClassName, currentExample.MethodName, currentExample.ExampleType.ToString(), mimeType); if (!_Examples.ContainsKey(key)) { _Examples.Add(key, currentExample); } else { SerialisationLog.Error(string.Concat("An example already exists for ", currentExample.ClassName, ".", currentExample.MethodName, ".", currentExample.ExampleType.ToString(), "files: [", currentExample.DocFilename, ", ", _Examples[key].DocFilename, "]")); } } else { SerialisationLog.Error(string.Concat("The method ", className, ".", methodName, " in ", filename, " does not exist")); } } } } } }
private string JsonToXml(Example currentExample, ResourceNode resourceTree, string json) { string xml = null; MethodInfo method = resourceTree.Find(currentExample.ClassName, currentExample.MethodName).Method; MethodDocumentationAttribute attribute = method.GetCustomAttributes <MethodDocumentationAttribute>().FirstOrDefault(); if (attribute != null) { Type objectType = null; if (currentExample.ExampleType == TMessageType.Request) { objectType = GetObjectType(attribute.RequestTypes, currentExample); } else { objectType = GetObjectType(attribute.ResponseTypes, currentExample); } if (objectType != null) { try { object deserialisedObject = JsonConvert.DeserializeObject(json, objectType); Stream stream = new MemoryStream(); XmlSerializer serializer = new XmlSerializer(objectType); XmlSerializerNamespaces xns = new XmlSerializerNamespaces(); xns.Add(string.Empty, string.Empty); serializer.Serialize(stream, deserialisedObject, xns); stream.Position = 0; using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { reader.ReadLine(); // skip <?xml version="1.0"?> xml = reader.ReadToEnd().Replace("+json", "+xml"); } } catch (InvalidOperationException) { SerialisationLog.Warning(string.Concat("Failed to serialise XML example for ", currentExample.ClassName, ".", currentExample.MethodName)); } catch (Exception ex) { if (ex is JsonReaderException || ex is JsonSerializationException) { SerialisationLog.Warning(string.Concat("Failed to deserialise JSON example for ", currentExample.ClassName, ".", currentExample.MethodName)); } else { throw; } } } else { SerialisationLog.Warning(string.Concat("No ", currentExample.ExampleType.ToString().ToLower(), " type for ", currentExample.ClassName, ".", currentExample.MethodName)); } } else { SerialisationLog.Warning(string.Concat("Could not convert JSON example to XML due to no method documentation for ", currentExample.ClassName, ".", currentExample.MethodName)); } return(xml); }
public static ResourceNode ReadAssembly(Assembly assembly) { ResourceNode tree = new ResourceNode(); Type[] types = assembly.GetTypes() .Where(t => t.IsSubclassOf(typeof(ControllerBase)) && t.GetCustomAttribute <RouteAttribute>() != null) .OrderBy(t => t.GetCustomAttribute <RouteAttribute>(), new RouteComparer()) .ToArray(); foreach (Type classType in types) { object[] attributes = classType.GetCustomAttributes(true); string resourceRoute = classType.GetCustomAttribute <RouteAttribute>().Template; if (resourceRoute != null) { MethodInfo[] methods = classType.GetMethods() .Where(m => m.GetCustomAttribute <HttpMethodAttribute>() != null) .OrderBy(m => m.GetCustomAttribute <HttpMethodAttribute>(), new MethodTemplateComparer()) .ToArray(); ResourceNode classNode = CreateResourceNode(tree, resourceRoute, classType); foreach (MethodInfo methodInfo in methods) { HttpMethodAttribute methodAttribute = methodInfo.GetCustomAttribute <HttpMethodAttribute>(); string httpMethod = methodAttribute.HttpMethods.FirstOrDefault().ToLower(); string template = null; bool rootTemplate = false; if (methodAttribute.Template != null) { template = string.Concat(methodAttribute.Template, "/"); if (!template.StartsWith("/")) { template = string.Concat("/", template); } else if (template.StartsWith(resourceRoute)) { template = template.Substring(resourceRoute.Length); } else { rootTemplate = true; } } else { template = "/"; } string fullPath = string.Concat(template, httpMethod); if (!rootTemplate) { fullPath = string.Concat(resourceRoute, fullPath); } ResourceNode methodNode = CreateResourceNode(tree, fullPath, classType); if (methodNode.Method != null) { SerialisationLog.Error(string.Concat("Multiple versions of ", methodNode.Class.Name, ".", methodNode.Method.Name, " exist")); } methodNode.Method = methodInfo; } } } return(tree); }