Open Closed

Errors while moving from Razor page UI to Angular #7726


User avatar
0
surajlokhandemmew created

ABP Framework version: v8.1.0

UI Type: MVC

Database System: MongoDB

Tiered (for MVC) or Auth Server Separated (for Angular): no

I created a new Angular-based project and adjusted the configuration, which resolved some issues. However, when I run abp generate-proxy -t ng, I encounter the following error: "[API Not Available] Request to https://localhost:44378/api/abp/api-definition is unsuccessful. Please double-check the URL in the source project environment and make sure your application is up and running."

The application is indeed running. Is there a way to configure this in a Razor Page project so that it can generate the Angular UI?


27 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    [API Not Available] Request to https://localhost:44378/api/abp/api-definition is unsuccessful

    what result if you request to the https://localhost:44378/api/abp/api-definition

  • User Avatar
    0
    surajlokhandemmew created

    I get a valid JSON response when I request the URL. Here's a screenshot for reference.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    it looks no problem

  • User Avatar
    0
    surajlokhandemmew created

    If there’s no issue, then what’s causing this problem? It’s strange because when I created a new project separately and integrated it for Razor Pages with the backend, the Identity module works fine. But now, I’m stuck and unable to generate the proxy for other modules.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    The CLI try to get API definitions from the Application, but https://localhost:44378/api/abp/api-definition can't reach

    you can see the code logic

  • User Avatar
    0
    surajlokhandemmew created

    Originally, when I created this Angular project, the endpoint was set to 44334. I later changed it in the environment file to 44378. Do I need to make changes anywhere else as well?

    i am getting below error in Audit Logs

    [ { "code": null, "message": "Given type () should be instance of System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (Parameter 'item')", "details": "ArgumentException: Given type () should be instance of System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (Parameter 'item')\r\nSTACK TRACE: at Volo.Abp.Http.Modeling.ApiTypeNameHelper.GetTypeName(Type type, ITypeList duplicateTypes)\r\n at Volo.Abp.Http.Modeling.PropertyApiDescriptionModel.Create(PropertyInfo propertyInfo)\r\n at System.Linq.Enumerable.WhereSelectArrayIterator`2.ToArray()\r\n at Volo.Abp.Http.Modeling.TypeApiDescriptionModel.Create(Type type)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, Type type)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, Type type)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, Type type)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, Type type)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, MethodInfo method)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel applicationModel, ApplicationApiDescriptionModelRequestDto input)\r\n at Volo.Abp.AspNetCore.Mvc.AspNetCoreApiDescriptionModelProvider.CreateApiModel(ApplicationApiDescriptionModelRequestDto input)\r\n at Volo.Abp.AspNetCore.Mvc.ApiExploring.AbpApiDefinitionController.Get(ApplicationApiDescriptionModelRequestDto model)\r\n at lambda_method5818(Closure, Object, Object[])\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    could you share a minimum reproducible project with me? i will check it.

    shiwei.liang@volosoft.com

  • User Avatar
    0
    surajlokhandemmew created

    When I try using Swagger with includeType=true, it throws an error.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    could you share a minimum reproducible project with me? i will check it. : )

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi, It's hard to find the problem in a few minutes.

    I guess the problem is related to your DTO property types.

    you can override the IApiDescriptionModelProvider service and check the logs.

    public static class ArrayMatcher
    {
        public static T[] Match<T>(T[] sourceArray, T[] destinationArray)
        {
            var result = new List<T>();
    
            var currentMethodParamIndex = 0;
            var parentItem = default(T);
    
            foreach (var sourceItem in sourceArray)
            {
                if (currentMethodParamIndex < destinationArray.Length)
                {
                    var destinationItem = destinationArray[currentMethodParamIndex];
    
                    if (EqualityComparer<T>.Default.Equals(sourceItem, destinationItem))
                    {
                        parentItem = default;
                        currentMethodParamIndex++;
                    }
                    else
                    {
                        if (parentItem == null)
                        {
                            parentItem = destinationItem;
                            currentMethodParamIndex++;
                        }
                    }
                }
    
                var resultItem = EqualityComparer<T>.Default.Equals(parentItem, default) ? sourceItem : parentItem;
                result.Add(resultItem!);
            }
    
            return result.ToArray();
        }
    }
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IApiDescriptionModelProvider))]
    public class MyAspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvider, ITransientDependency
    {
        public ILogger<MyAspNetCoreApiDescriptionModelProvider> Logger { get; set; }
    
        private readonly AspNetCoreApiDescriptionModelProviderOptions _options;
        private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider;
        private readonly AbpAspNetCoreMvcOptions _abpAspNetCoreMvcOptions;
        private readonly AbpApiDescriptionModelOptions _modelOptions;
    
        public MyAspNetCoreApiDescriptionModelProvider(
            IOptions<AspNetCoreApiDescriptionModelProviderOptions> options,
            IApiDescriptionGroupCollectionProvider descriptionProvider,
            IOptions<AbpAspNetCoreMvcOptions> abpAspNetCoreMvcOptions,
            IOptions<AbpApiDescriptionModelOptions> modelOptions)
        {
            _options = options.Value;
            _descriptionProvider = descriptionProvider;
            _abpAspNetCoreMvcOptions = abpAspNetCoreMvcOptions.Value;
            _modelOptions = modelOptions.Value;
    
            Logger = NullLogger<MyAspNetCoreApiDescriptionModelProvider>.Instance;
        }
    
        public ApplicationApiDescriptionModel CreateApiModel(ApplicationApiDescriptionModelRequestDto input)
        {
            //TODO: Can cache the model?
    
            var model = ApplicationApiDescriptionModel.Create();
    
            foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items)
            {
                foreach (var apiDescription in descriptionGroupItem.Items)
                {
                    if (!apiDescription.ActionDescriptor.IsControllerAction())
                    {
                        continue;
                    }
    
                    AddApiDescriptionToModel(apiDescription, model, input);
                }
            }
    
            foreach (var (_, module) in model.Modules)
            {
                var controllers = module.Controllers.GroupBy(x => x.Value.Type).ToList();
                foreach (var controller in controllers.Where(x => x.Count() > 1))
                {
                    var removedController = module.Controllers.RemoveAll(x => x.Value.IsRemoteService && controller.OrderBy(c => c.Value.ControllerGroupName).Skip(1).Contains(x));
                    foreach (var removed in removedController)
                    {
                        Logger.LogInformation($"The controller named '{removed.Value.Type}' was removed from ApplicationApiDescriptionModel because it same with other controller.");
                    }
                }
            }
    
            model.NormalizeOrder();
            return model;
        }
    
        private void AddApiDescriptionToModel(
            ApiDescription apiDescription,
            ApplicationApiDescriptionModel applicationModel,
            ApplicationApiDescriptionModelRequestDto input)
        {
            var controllerType = apiDescription
                .ActionDescriptor
                .AsControllerActionDescriptor()
                .ControllerTypeInfo;
    
            var setting = FindSetting(controllerType);
    
            var moduleModel = applicationModel.GetOrAddModule(
                GetRootPath(controllerType, apiDescription.ActionDescriptor, setting),
                GetRemoteServiceName(controllerType, setting)
            );
    
            var controllerModel = moduleModel.GetOrAddController(
                _options.ControllerNameGenerator(controllerType, setting),
                FindGroupName(controllerType) ?? apiDescription.GroupName,
                apiDescription.IsRemoteService(),
                apiDescription.IsIntegrationService(),
                apiDescription.GetProperty<ApiVersion>()?.ToString(),
                controllerType,
                _modelOptions.IgnoredInterfaces
            );
    
            var method = apiDescription.ActionDescriptor.GetMethodInfo();
    
            var uniqueMethodName = _options.ActionNameGenerator(method);
            if (controllerModel.Actions.ContainsKey(uniqueMethodName))
            {
                Logger.LogWarning(
                    $"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.RootPath}'. Ignored: " +
                    method);
                return;
            }
    
            Logger.LogDebug($"ActionApiDescriptionModel.Create: {controllerModel.ControllerName}.{uniqueMethodName}");
    
            bool? allowAnonymous = null;
            if (apiDescription.ActionDescriptor.EndpointMetadata.Any(x => x is IAllowAnonymous))
            {
                allowAnonymous = true;
            }
            else if (apiDescription.ActionDescriptor.EndpointMetadata.Any(x => x is IAuthorizeData))
            {
                allowAnonymous = false;
            }
    
            var implementFrom = controllerType.FullName;
    
            var interfaceType = controllerType.GetInterfaces().FirstOrDefault(i => i.GetMethods().Any(x => x.ToString() == method.ToString()));
            if (interfaceType != null)
            {
                implementFrom = TypeHelper.GetFullNameHandlingNullableAndGenerics(interfaceType);
            }
    
            var actionModel = controllerModel.AddAction(
                uniqueMethodName,
                ActionApiDescriptionModel.Create(
                    uniqueMethodName,
                    method,
                    apiDescription.RelativePath!,
                    apiDescription.HttpMethod,
                    GetSupportedVersions(controllerType, method, setting),
                    allowAnonymous,
                    implementFrom
                )
            );
    
            if (input.IncludeTypes)
            {
                AddCustomTypesToModel(applicationModel, method);
            }
    
            AddParameterDescriptionsToModel(actionModel, method, apiDescription);
        }
    
        private static List<string> GetSupportedVersions(Type controllerType, MethodInfo method,
            ConventionalControllerSetting? setting)
        {
            var supportedVersions = new List<ApiVersion>();
    
            var mapToAttributes = method.GetCustomAttributes<MapToApiVersionAttribute>().ToArray();
            if (mapToAttributes.Any())
            {
                supportedVersions.AddRange(
                    mapToAttributes.SelectMany(a => a.Versions)
                );
            }
            else
            {
                supportedVersions.AddRange(
                    controllerType.GetCustomAttributes<ApiVersionAttribute>().SelectMany(a => a.Versions)
                );
    
                setting?.ApiVersions.ForEach(supportedVersions.Add);
            }
    
            return supportedVersions.Select(v => v.ToString()).Distinct().ToList();
        }
    
        private void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, MethodInfo method)
        {
            foreach (var parameterInfo in method.GetParameters())
            {
                try
                {
                    AddCustomTypesToModel(applicationModel, parameterInfo.ParameterType);
                }
                catch(Exception e)
                {
                    Logger.LogError($"Error while adding parameter type to model, method info: {method.Name}, parameter info: {parameterInfo.Name}, parameter type: {parameterInfo.ParameterType.FullName}");
                    throw e;
                }
                
            }
    
            try
            {
                AddCustomTypesToModel(applicationModel, method.ReturnType);
            }
            catch (Exception e)
            {
                Logger.LogError($"Error while adding return type to model, method info: {method.Name}, return type: {method.ReturnType.FullName}");
                throw e;
            }
    
            
        }
    
        private static void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel,
            Type? type)
        {
            if (type == null)
            {
                return;
            }
    
            if (type.IsGenericParameter)
            {
                return;
            }
    
            type = AsyncHelper.UnwrapTask(type);
    
            if (type == typeof(object) ||
                type == typeof(void) ||
                type == typeof(Enum) ||
                type == typeof(ValueType) ||
                type == typeof(DateOnly) ||
                type == typeof(TimeOnly) ||
                TypeHelper.IsPrimitiveExtended(type))
            {
                return;
            }
    
            if (TypeHelper.IsDictionary(type, out var keyType, out var valueType))
            {
                AddCustomTypesToModel(applicationModel, keyType);
                AddCustomTypesToModel(applicationModel, valueType);
                return;
            }
    
            if (TypeHelper.IsEnumerable(type, out var itemType))
            {
                AddCustomTypesToModel(applicationModel, itemType);
                return;
            }
    
            if (type.IsGenericType && !type.IsGenericTypeDefinition)
            {
                var genericTypeDefinition = type.GetGenericTypeDefinition();
    
                AddCustomTypesToModel(applicationModel, genericTypeDefinition);
    
                foreach (var genericArgument in type.GetGenericArguments())
                {
                    AddCustomTypesToModel(applicationModel, genericArgument);
                }
    
                return;
            }
    
            var typeName = CalculateTypeName(type);
            if (applicationModel.Types.ContainsKey(typeName))
            {
                return;
            }
    
            applicationModel.Types[typeName] = TypeApiDescriptionModel.Create(type);
    
            AddCustomTypesToModel(applicationModel, type.BaseType);
    
            foreach (var propertyInfo in type.GetProperties().Where(p => p.DeclaringType == type))
            {
                AddCustomTypesToModel(applicationModel, propertyInfo.PropertyType);
            }
        }
    
        private static string CalculateTypeName(Type type)
        {
            if (!type.IsGenericTypeDefinition)
            {
                return TypeHelper.GetFullNameHandlingNullableAndGenerics(type);
            }
    
            var i = 0;
            var argumentList = type
                .GetGenericArguments()
                .Select(_ => "T" + i++)
                .JoinAsString(",");
    
            return $"{type.FullName!.Left(type.FullName!.IndexOf('`'))}&lt;{argumentList}&gt;";
        }
    
        private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method,
            ApiDescription apiDescription)
        {
            if (!apiDescription.ParameterDescriptions.Any())
            {
                return;
            }
    
            var parameterDescriptionNames = apiDescription
                .ParameterDescriptions
                .Select(p => p.Name)
                .ToArray();
    
            var methodParameterNames = method
                .GetParameters()
                .Where(IsNotFromServicesParameter)
                .Select(GetMethodParamName)
                .ToArray();
    
            var matchedMethodParamNames = ArrayMatcher.Match(
                parameterDescriptionNames,
                methodParameterNames
            );
    
            for (var i = 0; i &lt; apiDescription.ParameterDescriptions.Count; i++)
            {
                var parameterDescription = apiDescription.ParameterDescriptions[i];
                var matchedMethodParamName = matchedMethodParamNames.Length &gt; i
                    ? matchedMethodParamNames[i]
                    : parameterDescription.Name;
    
                actionModel.AddParameter(ParameterApiDescriptionModel.Create(
                        parameterDescription.Name,
                        _options.ApiParameterNameGenerator?.Invoke(parameterDescription),
                        matchedMethodParamName,
                        parameterDescription.Type,
                        parameterDescription.RouteInfo?.IsOptional ?? false,
                        parameterDescription.RouteInfo?.DefaultValue,
                        parameterDescription.RouteInfo?.Constraints?.Select(c => c.GetType().Name).ToArray(),
                        parameterDescription.Source.Id,
                        parameterDescription.ModelMetadata?.ContainerType != null
                            ? parameterDescription.ParameterDescriptor?.Name ?? string.Empty
                            : string.Empty
                    )
                );
            }
        }
    
        private static bool IsNotFromServicesParameter(ParameterInfo parameterInfo)
        {
            return !parameterInfo.IsDefined(typeof(FromServicesAttribute), true);
        }
    
        public string GetMethodParamName(ParameterInfo parameterInfo)
        {
            var modelNameProvider = parameterInfo.GetCustomAttributes()
                .OfType&lt;IModelNameProvider&gt;()
                .FirstOrDefault();
    
            if (modelNameProvider == null)
            {
                return parameterInfo.Name!;
            }
    
            return (modelNameProvider.Name ?? parameterInfo.Name)!;
        }
    
        private static string GetRootPath(
            [NotNull] Type controllerType,
            [NotNull] ActionDescriptor actionDescriptor,
            ConventionalControllerSetting? setting)
        {
            if (setting != null)
            {
                return setting.RootPath;
            }
    
            var areaAttr = controllerType.GetCustomAttributes().OfType&lt;AreaAttribute&gt;().FirstOrDefault() ?? actionDescriptor.EndpointMetadata.OfType&lt;AreaAttribute&gt;().FirstOrDefault();
            if (areaAttr != null)
            {
                return areaAttr.RouteValue;
            }
    
            return ModuleApiDescriptionModel.DefaultRootPath;
        }
    
        private string GetRemoteServiceName(Type controllerType, ConventionalControllerSetting? setting)
        {
            if (setting != null)
            {
                return setting.RemoteServiceName;
            }
    
            var remoteServiceAttr =
                controllerType.GetCustomAttributes().OfType&lt;RemoteServiceAttribute&gt;().FirstOrDefault();
            if (remoteServiceAttr?.Name != null)
            {
                return remoteServiceAttr.Name;
            }
    
            return ModuleApiDescriptionModel.DefaultRemoteServiceName;
        }
    
        private string? FindGroupName(Type controllerType)
        {
            var controllerNameAttribute =
                controllerType.GetCustomAttributes().OfType&lt;ControllerNameAttribute&gt;().FirstOrDefault();
    
            if (controllerNameAttribute?.Name != null)
            {
                return controllerNameAttribute.Name;
            }
    
            return null;
        }
    
        private ConventionalControllerSetting? FindSetting(Type controllerType)
        {
            foreach (var controllerSetting in _abpAspNetCoreMvcOptions.ConventionalControllers.ConventionalControllerSettings)
            {
                if (controllerSetting.GetControllerTypes().Contains(controllerType))
                {
                    return controllerSetting;
                }
            }
    
            return null;
        }
    }
    
  • User Avatar
    0
    surajlokhandemmew created

    I resolved the issue without needing to override the file—although the error message was ambiguous, the logs provided clear insight into the problem.

    Now, when I create a new module using yarn ng generate module tickets --route customerService --module app.module, it's generating empty components, and the URL isn't visible in the menu. How do I map the permissions for this? Or is there a different way to generate a complete UI using the ABP CLI?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    it's generating empty components, and the URL isn't visible in the menu. How do I map the permissions for this? Or is there a different way to generate a complete UI using the ABP CLI?

    you can use abp suite to generate code.

  • User Avatar
    0
    surajlokhandemmew created

    it's generating empty components, and the URL isn't visible in the menu. How do I map the permissions for this? Or is there a different way to generate a complete UI using the ABP CLI?

    you can use abp suite to generate code.

    ABP Suite generates the UI only for Razor Pages since the original project is based on Razor Pages. I copied this Angular project from a new project and configured it to work with the Razor Pages backend APIs. Is there any configuration file I can modify so that ABP Suite will generate Angular UIs instead?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    yes, you can open your .abp/suite folder to update the appsettings.json

    3 is Angular UI

  • User Avatar
    0
    surajlokhandemmew created

    There is no .abp folder, and within .studio or .abpstudio, there isn't an appsettings.json file either.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    %UserProfile%\.abp\suite

  • User Avatar
    0
    surajlokhandemmew created

    i am getting this error

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    The ng directory is incorrect .

    you can create a new ng project with suite to check what's the path config

  • User Avatar
    0
    surajlokhandemmew created

    It's the same, but it's still not working. Could this be because the host project URL is set to null?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    you can check the new project settings.

  • User Avatar
    0
    surajlokhandemmew created

    Can I mail you the file? Maybe you can spot the difference and help figure out what's going wrong.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    okay

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    1

    update to Angular

    2

    update HttpApiHostProjectDirectory

  • User Avatar
    0
    surajlokhandemmew created

    now it says angular ui generated and scucess popup comes up

    but no ui component is created in actual

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    could you share the suite logs?

Made with ❤️ on ABP v9.0.0-preview Updated on September 19, 2024, 10:13