예제 #1
0
        public void Read(ConfigurationBase configurationBase, List <ITransferObject> transferObjects)
        {
            ReflectionReadConfiguration configuration = (ReflectionReadConfiguration)configurationBase;
            Type type = GeneratorTypeLoader.Get(configuration, configuration.Assembly, configuration.Namespace, configuration.Name);

            if (type != null)
            {
                ModelTransferObject selfModel = this.modelReader.Read(type, transferObjects);
                if (configuration.SkipSelf)
                {
                    transferObjects.Remove(selfModel);
                    Logger.Trace($"{selfModel.Name} ({selfModel.Namespace}) skipped through configuration");
                }
            }
        }
예제 #2
0
        public void Read(ReflectionReadConfiguration configuration, IOptions caller = null)
        {
            Type type = GeneratorTypeLoader.Get(configuration.Assembly, configuration.Namespace, configuration.Name);

            if (type == null)
            {
                Logger.Trace($"Class {configuration.Namespace}.{configuration.Name} not found");
                return;
            }
            ModelTransferObject selfModel    = this.modelReader.Read(type, caller);
            IOptions            modelOptions = this.options.Get(selfModel);

            if (configuration.OnlySubTypes || modelOptions.OnlySubTypes)
            {
                modelOptions.OnlySubTypes = true;
            }
        }
        public override IGeneratorCommandResult Run()
        {
            Type type = GeneratorTypeLoader.Get(this.Parameters.Assembly, this.Parameters.Namespace, this.Parameters.Name);

            if (type == null)
            {
                Logger.Trace($"Class {this.Parameters.Namespace}.{this.Parameters.Name} not found");
                return(this.Error());
            }
            IOptions options = this.resolver.Get <Options>().Current;

            options.Language = this.resolver.Get <CsharpLanguage>();
            SqliteModelTransferObject model = this.resolver.Create <SqliteModelReader>().Read(type);

            this.resolver.Get <IOutput>().DeleteAllRelatedFiles(this.Parameters.RelativePath);
            this.resolver.Create <SqliteRepositoryWriter>().Write(model, this.Parameters);
            return(this.Success());
        }
        public virtual void Read(AspDotNetReadConfiguration configuration)
        {
            configuration.Controller.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}");
            configuration.Controller.Name.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}.{nameof(configuration.Controller.Name)}");
            configuration.Controller.Namespace.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}.{nameof(configuration.Controller.Namespace)}");
            Logger.Trace($"Read ASP.NET controller {configuration.Controller.Namespace}.{configuration.Controller.Name}...");
            Type type = GeneratorTypeLoader.Get(configuration.Controller.Assembly, configuration.Controller.Namespace, configuration.Controller.Name);

            if (type == null)
            {
                return;
            }

            HttpServiceTransferObject controller = new();

            controller.Name     = type.Name;
            controller.Language = ReflectionLanguage.Instance;

            IOptions typeOptions = this.options.Get(type);

            this.options.Set(controller, typeOptions);
            IAspDotNetOptions typeAspOptions = this.aspOptions.Get(type);

            this.aspOptions.Set(controller, typeAspOptions);
            controller.Route   = typeAspOptions.Route;
            controller.Version = typeAspOptions.ApiVersion?.LastOrDefault();

            List <MethodInfo> methods = new();
            Type currentTyp           = type;

            while (currentTyp?.Namespace != null && !currentTyp.Namespace.StartsWith("Microsoft") && !currentTyp.Namespace.StartsWith("System"))
            {
                IOptions currentOptions = this.options.Get(currentTyp);
                if (currentOptions.Ignore)
                {
                    break;
                }
                methods.AddRange(currentTyp.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
                                 // Remove all overwritten methods
                                 .Where(method => methods.All(m => m.GetBaseDefinition() != method))
                                 );
                currentTyp = currentTyp.BaseType;
            }
            foreach (MethodInfo method in methods)
            {
                IOptions          methodOptions    = this.options.Get(method);
                IAspDotNetOptions methodAspOptions = this.aspOptions.Get(method);
                if (methodOptions.Ignore || methodAspOptions.IsNonAction)
                {
                    continue;
                }

                Dictionary <HttpServiceActionTypeTransferObject, string> actionTypes = this.GetActionTypes(methodAspOptions);
                if (actionTypes.Count == 0)
                {
                    Logger.Error($"{type.FullName}.{method.Name} has to be decorated with at least one of [HttpGet], [HttpPost], [HttpPut], [HttpPatch], [HttpDelete], [NonAction] or with [GenerateIgnore].");
                    continue;
                }
                Type returnType = (methodAspOptions.Produces ?? method.ReturnType)
                                  .IgnoreGeneric("System.Threading.Tasks", "Task")
                                  .IgnoreGeneric("Microsoft.AspNetCore.Mvc", "IActionResult")
                                  .IgnoreGeneric("Microsoft.AspNetCore.Mvc", "ActionResult")
                                  .IgnoreGeneric("System.Web.Mvc", "ActionResult")
                                  .IgnoreGeneric("System.Web.Mvc", "ContentResult")
                                  .IgnoreGeneric("System.Web.Mvc", "EmptyResult")
                                  .IgnoreGeneric("System.Web.Mvc", "FileContentResult")
                                  .IgnoreGeneric("System.Web.Mvc", "FilePathResult")
                                  .IgnoreGeneric("System.Web.Mvc", "FileResult")
                                  .IgnoreGeneric("System.Web.Mvc", "FileStreamResult")
                                  .IgnoreGeneric("System.Web.Mvc", "JsonResult")
                                  .IgnoreGeneric(typeAspOptions.IgnoreGenerics)
                                  .IgnoreGeneric(methodAspOptions.IgnoreGenerics);

                Type returnEntryType = returnType.IgnoreGeneric(typeof(IEnumerable <>)).IgnoreGeneric(typeof(List <>)).IgnoreGeneric(typeof(IList <>));
                IAspDotNetOptions returnEntryTypeOptions = this.aspOptions.Get(returnEntryType, methodAspOptions);
                foreach (KeyValuePair <HttpServiceActionTypeTransferObject, string> actionType in actionTypes)
                {
                    HttpServiceActionTransferObject action = new();
                    action.Name       = actionTypes.Count == 1 ? method.Name : $"{actionType.Key}{method.Name.FirstCharToUpper()}";
                    action.ReturnType = this.modelReader.Read(returnType, methodOptions);
                    action.Route      = actionType.Value ?? methodAspOptions.Route;
                    if (action.Route?.Contains(":") ?? false)
                    {
                        action.Route = Regex.Replace(action.Route, "({[^:]*)((:apiVersion)|:[^}?]+)(\\??})", "$1$3$4");
                    }
                    action.Type    = actionType.Key;
                    action.Version = methodAspOptions.ApiVersion?.OrderByDescending(x => x).FirstOrDefault();
                    action.FixCasingWithMapping = returnEntryTypeOptions.FixCasingWithMapping || methodAspOptions.FixCasingWithMapping;
                    action.RequireBodyParameter = action.Type.IsBodyParameterRequired();
                    List <ParameterInfo> parameters = method.GetParameters().Where(
                        parameter => !this.aspOptions.Get(parameter, methodAspOptions).IsFromHeader &&
                        !this.aspOptions.Get(parameter, methodAspOptions).IsFromServices &&
                        parameter.ParameterType.FullName != "System.Threading.CancellationToken"
                        ).ToList();
                    foreach (ParameterInfo parameter in parameters)
                    {
                        IAspDotNetOptions parameterOptions = this.aspOptions.Get(parameter, methodAspOptions);
                        string            fullRoute        = $"{controller.Route}/{action.Route}";
                        HttpServiceActionParameterTransferObject actionParameter = new();
                        actionParameter.Name        = parameter.Name;
                        actionParameter.Type        = this.modelReader.Read(parameter.ParameterType, methodOptions);
                        actionParameter.FromBody    = parameterOptions.IsFromBody || action.Type != HttpServiceActionTypeTransferObject.Get && !parameter.ParameterType.IsValueType && parameter.ParameterType != typeof(string);
                        actionParameter.FromQuery   = parameterOptions.IsFromQuery;
                        actionParameter.Inline      = fullRoute.Contains($"{{{parameter.Name}}}");
                        actionParameter.InlineIndex = actionParameter.Inline && action.Route != null?action.Route.IndexOf($"{{{parameter.Name}}}") : 0;

                        actionParameter.IsOptional = parameter.IsOptional;
                        if (fullRoute.Contains($"{{{parameter.Name}?}}"))
                        {
                            actionParameter.Inline      = true;
                            actionParameter.IsOptional  = true;
                            actionParameter.InlineIndex = fullRoute.IndexOf($"{{{parameter.Name}?}}");
                            action.Route = action.Route.Replace($"{{{parameter.Name}?}}", $"{{{parameter.Name}}}");
                        }
                        action.Parameters.Add(actionParameter);
                        if (action.Type == HttpServiceActionTypeTransferObject.Get && actionParameter.Type.Name == "List" && !actionParameter.FromQuery)
                        {
                            Logger.Error($"HttpGet methods with list parameter '{parameter.Name}' of {type.FullName}.{method.Name} has to be decorated with [FromQuery]");
                        }
                    }
                    if (action.RequireBodyParameter)
                    {
                        if (action.Parameters.Count == 0)
                        {
                            throw new InvalidOperationException($"Can not write {method.Name}. {action.Type} requires at least one parameter, but no parameter found. Use [GenerateIgnore] to skip generation for that method");
                        }
                        if (action.Parameters.Count == 1)
                        {
                            action.Parameters.Single().FromBody = true;
                        }
                        else if (action.Parameters.All(x => !x.FromBody))
                        {
                            throw new InvalidOperationException($"Can not write {method.Name}. {action.Type} requires at least one parameter marked with [FromBody] or can have only one parameter");
                        }
                    }
                    if (action.Parameters.Count(x => x.FromBody) > 1)
                    {
                        throw new InvalidOperationException($"Can not write {method.Name}. {action.Type} can have only one parameter marked with [FromBody] or only one reference type");
                    }
                    int tries = 0;
                    while (controller.Actions.Any(a => a.Name == action.Name))
                    {
                        if (tries > 10)
                        {
                            throw new InvalidOperationException($"Can not find a suitable name for {action.Name}");
                        }
                        if (parameters.Count > 0 && tries == 0)
                        {
                            action.Name += "By" + parameters.First().Name.FirstCharToUpper();
                        }
                        else if (parameters.Count > tries)
                        {
                            action.Name += "And" + parameters.Skip(tries).First().Name.FirstCharToUpper();
                        }
                        else
                        {
                            action.Name += tries - parameters.Count + 1;
                        }
                        tries++;
                    }
                    controller.Actions.Add(action);
                }
            }
            transferObjects.Add(controller);
        }
예제 #5
0
        public void Read(AspDotNetReadConfiguration configuration)
        {
            configuration.Hub.AssertIsNotNull($"SignalR: {nameof(configuration.Hub)}");
            configuration.Hub.Name.AssertIsNotNull($"SignalR: {nameof(configuration.Hub)}.{nameof(configuration.Hub.Name)}");
            configuration.Hub.Namespace.AssertIsNotNull($"SignalR: {nameof(configuration.Hub)}.{nameof(configuration.Hub.Namespace)}");
            Logger.Trace($"Read SignalR hub {configuration.Hub.Namespace}.{configuration.Hub.Name}...");
            Type type = GeneratorTypeLoader.Get(configuration.Hub.Assembly, configuration.Hub.Namespace, configuration.Hub.Name);

            if (type == null || type.BaseType == null || type.BaseType.Name != "Hub`1")
            {
                return;
            }
            if (!type.BaseType.IsGenericType)
            {
                Logger.Error("Implement generic Hub<T> instead of non-generic Hub type");
            }

            SignalRHubTransferObject hub = new();

            hub.Name     = type.Name;
            hub.Language = ReflectionLanguage.Instance;

            IAspDotNetOptions typeOptions = this.aspOptions.Get(type);

            this.aspOptions.Set(hub, typeOptions);

            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (MethodInfo method in methods)
            {
                if (method.Name == "OnConnectedAsync" || method.Name == "OnDisconnectedAsync")
                {
                    continue;
                }
                IOptions methodOptions = this.options.Get(method);
                HttpServiceActionTransferObject action = new();
                action.Name = method.Name;
                if (method.ReturnType.Name != typeof(void).Name && method.ReturnType.Name != nameof(Task))
                {
                    Logger.Error($"Return type of method {method.Name} in {hub.Name} has to be void or Task");
                }
                foreach (ParameterInfo parameter in method.GetParameters())
                {
                    action.Parameters.Add(new HttpServiceActionParameterTransferObject
                    {
                        Name = parameter.Name,
                        Type = this.modelReader.Read(parameter.ParameterType, methodOptions)
                    });
                }
                hub.Actions.Add(action);
            }

            Type notificationType = type.BaseType.GetGenericArguments().Single();

            MethodInfo[] notificationMethods = notificationType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (MethodInfo method in notificationMethods)
            {
                IOptions methodOptions = this.options.Get(method);
                HttpServiceActionTransferObject action = new();
                action.Name = method.Name;
                foreach (ParameterInfo parameter in method.GetParameters())
                {
                    action.Parameters.Add(new HttpServiceActionParameterTransferObject
                    {
                        Name = parameter.Name,
                        Type = this.modelReader.Read(parameter.ParameterType, methodOptions)
                    });
                }
                hub.Events.Add(action);
            }
            transferObjects.Add(hub);
        }
        public virtual void Read(AspDotNetReadConfiguration configuration, List <ITransferObject> transferObjects)
        {
            configuration.Controller.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}");
            configuration.Controller.Name.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}.{nameof(configuration.Controller.Name)}");
            configuration.Controller.Namespace.AssertIsNotNull($"ASP: {nameof(configuration.Controller)}.{nameof(configuration.Controller.Namespace)}");
            Logger.Trace($"Read ASP.NET controller {configuration.Controller.Namespace}{configuration.Controller.Name}...");
            Type type = GeneratorTypeLoader.Get(configuration, configuration.Controller.Assembly, configuration.Controller.Namespace, configuration.Controller.Name);

            if (type == null)
            {
                return;
            }

            HttpServiceTransferObject controller = new HttpServiceTransferObject();

            controller.Name     = type.Name;
            controller.Language = ReflectionLanguage.Instance;

            Attribute routeAttribute = type.GetCustomAttributes().FirstOrDefault();

            controller.Route = routeAttribute?.GetType().GetProperty("Template")?.GetValue(routeAttribute)?.ToString();

            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (MethodInfo method in methods)
            {
                this.modelReader.Read(method.ReturnType, transferObjects);
                foreach (Attribute attribute in method.GetCustomAttributes())
                {
                    Type attributeType = attribute.GetType();
                    HttpServiceActionTransferObject action = new HttpServiceActionTransferObject();
                    action.ReturnType = method.ReturnType.ToTransferObject();
                    if (action.ReturnType.Name == "ActionResult")
                    {
                        action.ReturnType = action.ReturnType.Generics.Single().Type;
                    }
                    action.Route = attributeType.GetProperty("Template")?.GetValue(attribute)?.ToString();
                    int methodNameIndex = 1;
                    while (true)
                    {
                        string actionName = $"{method.Name}{(methodNameIndex > 1 ? methodNameIndex.ToString() : "")}";
                        if (controller.Actions.All(x => !x.Name.Equals(actionName)))
                        {
                            action.Name = actionName;
                            break;
                        }
                        methodNameIndex++;
                    }
                    ParameterInfo[] parameters = method.GetParameters();
                    foreach (ParameterInfo parameter in parameters)
                    {
                        this.modelReader.Read(parameter.ParameterType, transferObjects);
                    }
                    switch (attributeType.Name)
                    {
                    case "HttpGetAttribute":
                        action.Type = HttpServiceActionTypeTransferObject.Get;
                        break;

                    case "HttpPostAttribute":
                        action.Type = HttpServiceActionTypeTransferObject.Post;
                        break;

                    case "HttpPatchAttribute":
                        action.Type = HttpServiceActionTypeTransferObject.Patch;
                        break;

                    case "HttpPutAttribute":
                        action.Type = HttpServiceActionTypeTransferObject.Put;
                        break;

                    case "HttpDeleteAttribute":
                        action.Type = HttpServiceActionTypeTransferObject.Delete;
                        break;

                    case "ConditionalAttribute":
                        // Ignore these attributes
                        continue;

                    default:
                        Logger.Warning($"Unknown controller action attribute {attributeType.Name}");
                        continue;
                    }
                    action.RequireBodyParameter = action.Type.IsBodyParameterRequired();
                    foreach (ParameterInfo parameter in parameters)
                    {
                        HttpServiceActionParameterTransferObject actionParameter = new HttpServiceActionParameterTransferObject();
                        actionParameter.Name        = parameter.Name;
                        actionParameter.Type        = parameter.ParameterType.ToTransferObject();
                        actionParameter.FromBody    = action.RequireBodyParameter && parameter.GetCustomAttributes().Any(parameterAttribute => parameterAttribute.GetType().Name == "FromBodyAttribute");
                        actionParameter.Inline      = action.Route != null && action.Route.Contains($"{{{parameter.Name}}}");
                        actionParameter.InlineIndex = actionParameter.Inline ? action.Route.IndexOf($"{{{parameter.Name}}}", StringComparison.Ordinal) : 0;
                        action.Parameters.Add(actionParameter);
                    }
                    if (action.RequireBodyParameter)
                    {
                        if (action.Parameters.Count == 0)
                        {
                            throw new InvalidOperationException($"Can not write {method.Name}. {action.Type} requires at least one parameter, but no parameter found.");
                        }
                        if (action.Parameters.Count == 1)
                        {
                            action.Parameters.Single().FromBody = true;
                        }
                        else if (action.Parameters.All(x => !x.FromBody))
                        {
                            throw new InvalidOperationException($"Can not write {method.Name}. {action.Type} requires at least one parameter marked with [FromBody] or can have only one parameter");
                        }
                    }
                    controller.Actions.Add(action);
                }
            }
            transferObjects.Add(controller);
        }