public ActionsGroupNode ReadController(Type type, AssemblyNode assemblyNode) { var controller = new ActionsGroupNode { Assembly = assemblyNode }; string routePrefix = null; var routePrefixAttribute = type.GetTypeInfo().GetCustomAttribute<RouteAttribute>(false) ?? type.GetTypeInfo().GetCustomAttribute<RouteAttribute>(); if (routePrefixAttribute != null) { routePrefix = routePrefixAttribute.Template; } controller.Name = type.Name.Replace("Controller", string.Empty); controller.Name = NameCleaner.Replace(controller.Name, string.Empty); controller.Documentation = documentation.GetDocumentation(type); foreach (var methodInfo in type.GetMethods().Where(x => x.IsPublic)) { if (methodInfo.GetCustomAttribute<NonActionAttribute>() != null) continue; if (methodInfo.IsSpecialName) continue; var action = ReadAction(routePrefix, methodInfo, controller); if (action != null) { controller.Actions.Add(action); } } return controller; }
public ActionNode(ActionsGroupNode actionsGroupNode, string name, string route) => (Group, Name, Route) = (actionsGroupNode, name, route);
private void WriteController(ActionsGroupNode controllerNode) { var result = new StringBuilder(); result.AppendLine("/* This is a generated file. Do not modify or all the changes will be lost. */"); result.AppendLine($"import * as helpers from '{serviceHelpersModule}';"); result.AppendLine("import * as views from './views';"); result.AppendLine("import * as koViews from './ko-views';"); var controllersOutput = new StringBuilder(); AppendFormatDocumentation(controllersOutput, controllerNode.Documentation); controllersOutput.AppendLine($"export class {controllerNode.Name}Controller {{"); WriteActions(controllerNode, controllersOutput); controllersOutput.AppendLine("}"); controllersOutput.AppendLine(); var moduleName = StringHelpers.ToCamelCase(controllerNode.Name); result.AppendLine(); result.Append(controllersOutput); OutputModules.Add(moduleName, result.ToString()); }
private void WriteActions(ActionsGroupNode controllerNode, StringBuilder controllersOutput) { var actions = controllerNode.Actions.OrderBy(x => x.Name).ThenBy(x => x.Parameters.Count).ToArray(); foreach (var actionNode in actions) { var methodName = StringHelpers.ToCamelCase(actionNode.Name); var sameName = actions.Where(x => x.Name == actionNode.Name).ToList(); if (sameName.Count > 1) { methodName += sameName.IndexOf(actionNode) + 1; } WriteAction(methodName, actionNode, controllersOutput, true); if (actionNode.Return != null && actionNode.Return.Type.IsObservable) WriteAction(methodName + "T", actionNode, controllersOutput, false); } }
public ActionNode ReadAction(string routePrefix, MethodInfo methodInfo, ActionsGroupNode actionsGroup) { var actionNode = new ActionNode {Group = actionsGroup}; string route = null; if (methodInfo.GetCustomAttribute<HttpGetAttribute>() != null) { actionNode.Type = ActionMethod.Get; route = methodInfo.GetCustomAttribute<HttpGetAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpPostAttribute>() != null) { actionNode.Type = ActionMethod.Post; route = methodInfo.GetCustomAttribute<HttpPostAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpPutAttribute>() != null) { actionNode.Type = ActionMethod.Put; route = methodInfo.GetCustomAttribute<HttpPutAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpDeleteAttribute>() != null) { actionNode.Type = ActionMethod.Delete; route = methodInfo.GetCustomAttribute<HttpDeleteAttribute>().Template; } var routeAttribute = methodInfo.GetCustomAttribute<RouteAttribute>(); if (routeAttribute != null) { route = routeAttribute.Template; } if (route == null) { return null; } if (actionNode.Type == ActionMethod.Unknown) { if (methodInfo.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Get; else if (methodInfo.Name.StartsWith("Post", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Post; else if (methodInfo.Name.StartsWith("Put", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Put; else if (methodInfo.Name.StartsWith("Delete", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Delete; else return null; } // Remove type info from route route = Regex.Replace(route, @"{(\w+\??)(?::\w+)?}", "{$1}"); if (route.StartsWith("~")) { route = Regex.Replace(route, @"^~/?", string.Empty); } else { route = $"{routePrefix}/{route}"; } actionNode.Name = methodInfo.Name; actionNode.Route = route; var versionMatch = Regex.Match(route, @"api/v([\d\.])+"); actionNode.Version = versionMatch.Success ? versionMatch.Groups[1].Value : null; var authorizeAttribute = methodInfo.GetCustomAttribute<AuthorizeAttribute>(); if (authorizeAttribute != null) { actionNode.Authorization = authorizeAttribute.Policy ?? authorizeAttribute.Roles; } // Read documentation var methodNode = documentation.GetMethodDocumentation(methodInfo); var summary = methodNode?.Element("summary"); if (summary != null) { actionNode.Documentation = summary.Value; } Dictionary<string, XElement> parameterNodes = null; if (methodNode != null) { parameterNodes = methodNode.Elements("param").ToDictionary(x => x.Attribute("name").Value); } var routeParameters = new Dictionary<string, bool>(); var routeParametersMatches = Regex.Matches(route, @"{(\w+)(\?)?(?:\:\w+)?}"); foreach (Match match in routeParametersMatches) { var parameter = match.Groups[1].Value; var optional = match.Groups[2].Value == "?"; routeParameters.Add(parameter, optional); } foreach (var parameterInfo in methodInfo.GetParameters()) { var parameter = ReadParameter(parameterInfo, parameterNodes != null && parameterNodes.ContainsKey(parameterInfo.Name) ? parameterNodes[parameterInfo.Name] : null, actionsGroup.Assembly, routeParameters, actionNode.Version); actionNode.Parameters.Add(parameter); if (parameter.Position == ParameterPosition.Body) { parameter.Type.SetWritable(); } } Type returnType; var returnTypeAttribute = methodInfo.GetCustomAttribute<ProducesResponseTypeAttribute>(); if (returnTypeAttribute != null) { returnType = returnTypeAttribute.Type; } else { returnType = methodInfo.ReturnType; if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) { returnType = returnType.GenericTypeArguments[0]; } if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IHttpActionResult<>)) { returnType = returnType.GenericTypeArguments[0]; } if (returnType.GetInterfaces().Contains(typeof(IActionResult)) || returnType == typeof(IActionResult) || returnType == typeof(Task)) { returnType = null; } } if (returnType != null && returnType != typeof(void)) { var returnDocumentation = methodNode?.Element("returns"); actionNode.Return = ReadReturn(returnType, actionsGroup.Assembly, returnDocumentation, actionNode.Version); } return actionNode; }