Activities of "MichelZ"

Going further with this, I have tried it using just ASP.NET Core, and the type seems to be represented just fine in ApiExplorer with this. I'll send you the project

Actually, going further it seems the issue is not class vs struct, but that the type is used in a route path, e.g:

        [HttpPost("/class/{testClass}")]
        public ActionResult FromTestClass(TestClass testClass)
        {
            return NoContent();
        }

This produces 2 parameters, one for the route {testClass} with no Type and one for the function itself with the correct type info.

So this seems to be the culprit here

Going further with this, I have tried it using just ASP.NET Core, and the type seems to be represented just fine in ApiExplorer with this. I'll send you the project

It must be something with ASP.NET Core then (or the way ABP uses the information), you can get rid of StronglyTypedId package / code and just use this for AgentId:

namespace Repro.ProxyGeneration.Models.Test
{
    public struct AgentId
    {
        public int Value { get; }

        public AgentId(int value)
        {
            Value = value;
        }
    }
}

This leads to the same issue. The workaround seems to work and my proxies do get generated again, thank you

From what I can see is that it fails here in @abp\ng.schematics\utils\common.js

Object.values(controller.actions || {}).forEach(a => {
            a.returnValue.type = sanitizeTypeName(a.returnValue.type);
            a.returnValue.typeSimple = sanitizeTypeName(a.returnValue.typeSimple);
            a.parametersOnMethod?.forEach(p => {
                p.type = sanitizeTypeName(p.type);
                p.typeAsString = sanitizeTypeName(p.typeAsString);
                p.typeSimple = sanitizeTypeName(p.typeSimple);
            });
            a.parameters?.forEach(p => {
                p.type = sanitizeTypeName(p.type);
                p.typeSimple = sanitizeTypeName(p.typeSimple);
            });
        });

Specifically here:

a.parameters?.forEach(p => {
                p.type = sanitizeTypeName(p.type);   <--------
                p.typeSimple = sanitizeTypeName(p.typeSimple);
            });

Looking into my api-definition, I get for instance this generated parameter on a method:

"paramters": [
     {
                                    "nameOnMethod": "agentApiKeyId",
                                    "name": "agentApiKeyId",
                                    "jsonName": null,
                                    "type": null,
                                    "typeSimple": null,
                                    "isOptional": false,
                                    "defaultValue": null,
                                    "constraintTypes": [],
                                    "bindingSourceId": "Path",
                                    "descriptorName": ""
                                }
     ]

notice how the type is null.

This particular method is in a Controller (however we observe the same from ApplicationServices as well):

    [HttpPost]
    [Route("api-keys/{agentApiKeyId}")]
    public async Task<ActionResult> SetAgentApiKeyStatusAsync(AgentApiKeyId agentApiKeyId, bool isEnabled)
    {
        await _agentAppService.SetApiKeyStatusAsync(agentApiKeyId, isEnabled);
        return NoContent();
    }

Now, AgentApiKeyId itself is a value object struct (generated by the StronglyTypedId project) :

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the StronglyTypedId source generator
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#pragma warning disable 1591 // publicly visible type or member must be documented

namespace MyCompany.MyProject.Agent.ValueObjectId
{
    [System.Text.Json.Serialization.JsonConverter(typeof(AgentApiKeyIdSystemTextJsonConverter))]
    [System.ComponentModel.TypeConverter(typeof(AgentApiKeyIdTypeConverter))]
    readonly partial struct AgentApiKeyId : System.IComparable<AgentApiKeyId>, System.IEquatable<AgentApiKeyId>
    {
        public int Value { get; }

        public AgentApiKeyId(int value)
        {
            Value = value;
        }

        public static readonly AgentApiKeyId Empty = new AgentApiKeyId(0);

        public bool Equals(AgentApiKeyId other) => this.Value.Equals(other.Value);
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is AgentApiKeyId other && Equals(other);
        }

        public override int GetHashCode() => Value.GetHashCode();

        public override string ToString() => Value.ToString();
        public static bool operator ==(AgentApiKeyId a, AgentApiKeyId b) => a.Equals(b);
        public static bool operator !=(AgentApiKeyId a, AgentApiKeyId b) => !(a == b);
        public int CompareTo(AgentApiKeyId other) => Value.CompareTo(other.Value);

        public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<AgentApiKeyId, int>
        {
            public EfCoreValueConverter() : this(null) { }
            public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
                : base(
                    id => id.Value,
                    value => new AgentApiKeyId(value),
                    mappingHints
                ) { }
        }

        class AgentApiKeyIdTypeConverter : System.ComponentModel.TypeConverter
        {
            public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
            {
                return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }

            public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
            {
                return value switch
                {
                    int intValue => new AgentApiKeyId(intValue),
                    string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new AgentApiKeyId(result),
                    _ => base.ConvertFrom(context, culture, value),
                };
            }

            public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
            {
                return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
            }

            public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
            {
                if (value is AgentApiKeyId idValue)
                {
                    if (destinationType == typeof(int))
                    {
                        return idValue.Value;
                    }

                    if (destinationType == typeof(string))
                    {
                        return idValue.Value.ToString();
                    }
                }

                return base.ConvertTo(context, culture, value, destinationType);
            }
        }

        class AgentApiKeyIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter<AgentApiKeyId>
        {
            public override AgentApiKeyId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
            {
                return new AgentApiKeyId(reader.GetInt32());
            }

            public override void Write(System.Text.Json.Utf8JsonWriter writer, AgentApiKeyId value, System.Text.Json.JsonSerializerOptions options)
            {
                writer.WriteNumberValue(value.Value);
            }
        }
    }
}

It seems like struct's are not correctly processed when generating the api-definition. Is this something that can be fixed?

I was able to get a stack trace by using this: yarn nx g @abp/nx.generators:generate-proxy --verbose maybe it helps?

TypeError: Cannot read properties of null (reading 'replace')
    at sanitizeTypeName (W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\utils\common.js:35:41)
    at W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\utils\common.js:58:26
    at Array.forEach (<anonymous>)
    at W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\utils\common.js:57:27
    at Array.forEach (<anonymous>)
    at W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\utils\common.js:49:49
    at Array.forEach (<anonymous>)
    at sanitizeControllerTypeNames (W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\utils\common.js:37:38)
    at W:\DEV\ProductName\abp\angular\node_modules\@abp\ng.schematics\commands\api\index.js:31:92
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
{
  "name": "ProductName",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --open",
    "start:development-staging": "ng server --open --configuration development-staging",
    "build": "ng build",
    "build:docker-compose": "ng build --configuration docker-compose",
    "build:development-staging": "ng build --configuration development-staging",
    "build:prod": "ng build --configuration production",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint"
  },
  "private": true,
  "dependencies": {
    "@abp/ng.components": "~7.4.2",
    "@abp/ng.core": "~7.4.2",
    "@abp/ng.oauth": "~7.4.2",
    "@abp/ng.setting-management": "~7.4.2",
    "@abp/ng.theme.shared": "~7.4.2",
    "@amcharts/amcharts4": "^4.10.38",
    "@angular-builders/jest": "^16.0.0",
    "@angular/animations": "^16.2.12",
    "@angular/common": "^16.2.12",
    "@angular/compiler": "^16.2.12",
    "@angular/core": "^16.2.12",
    "@angular/forms": "^16.2.12",
    "@angular/localize": "16.2.12",
    "@angular/platform-browser": "^16.2.12",
    "@angular/platform-browser-dynamic": "^16.2.12",
    "@angular/router": "^16.2.12",
    "@chiragrupani/karma-chromium-edge-launcher": "^2.1.1",
    "@ngxs/store": "^3.7.6",
    "@swimlane/ngx-charts": "^20.0.0",
    "@volo/abp.commercial.ng.ui": "~7.4.2",
    "@volo/abp.ng.account": "~7.4.2",
    "@volo/abp.ng.audit-logging": "~7.4.2",
    "@volo/abp.ng.gdpr": "~7.4.2",
    "@volo/abp.ng.identity": "~7.4.2",
    "@volo/abp.ng.language-management": "~7.4.2",
    "@volo/abp.ng.openiddictpro": "~7.4.2",
    "@volo/abp.ng.saas": "~7.4.2",
    "@volo/abp.ng.text-template-management": "~7.4.2",
    "@volo/abp.ng.theme.lepton": "7.4.2",
    "@volo/language-management": "~7.4.2",
    "@yaireo/tagify": "^4.17.0",
    "bootstrap-icons": "^1.11.2",
    "jest": "^29.7.0",
    "karma-junit-reporter": "^2.0.1",
    "ngx-bootstrap-multiselect": "^4.0.0",
    "ngx-editor": "^16.0.0",
    "rxjs": "7.8.1",
    "tslib": "^2.1.0",
    "zone.js": "~0.13.3"
  },
  "devDependencies": {
    "@abp/ng.schematics": "~7.4.2",
    "@angular-devkit/build-angular": "^16.2.10",
    "@angular-eslint/builder": "16.3.1",
    "@angular-eslint/eslint-plugin": "16.3.1",
    "@angular-eslint/eslint-plugin-template": "16.3.1",
    "@angular-eslint/schematics": "16.3.1",
    "@angular-eslint/template-parser": "16.3.1",
    "@angular/cli": "^16.2.10",
    "@angular/compiler-cli": "^16.2.12",
    "@angular/language-service": "^16.2.12",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^18.11.0",
    "@typescript-eslint/eslint-plugin": "^5.59.2",
    "@typescript-eslint/parser": "^5.59.2",
    "eslint": "^8.39.0",
    "jasmine-core": "~4.0.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.1.0",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.7.0",
    "ng-packagr": "^16.2.3",
    "typescript": "~5.1.6"
  },
  "resolutions": {
    "prosemirror-view": "1.31.7"
  }
}

We have tried this with the application before-upgrade now (v6.0.2) and it worked (I stated previously that it didn't, but I executed it in the wrong directory)

So it seems there is some issue with the upgrade from 6.0.2 to 7.4.2? Any pointers?

We have tried with version 7.4.2 now, with the same result.

Hi,

Above stack overflow discussion is about 2 scenarios

  1. If there is no model/service then also you are trying to generate proxy
  2. If you are targeting to live API address instead of local one
  1. We do have services of course
  2. We are not targeting live API, abp generate-proxy -t ng -u http://localhost:5101 <--- Localhost!

> If these are not the case then please check

  1. Check your ABP Framework and CLI version are same or not?

CLI is .1 newer (7.4.3 vs 7.4.2)

  1. or once run npm install to install all the necessary dependencies and then try

The frontend builds fine with ng build / ng serve. Packages are all installed

yarn install v1.22.19 [1/4] Resolving packages... success Already up-to-date. Done in 0.42s.

Hello,

Have you checked this https://stackoverflow.com/questions/70278156/abp-io-angular-cannot-read-property-replace-of-undefined

Have you followed these migration guides https://docs.abp.io/en/abp/latest/Migration-Guides/Index

Please check once and let me know if found helpful.

Thanks

We have followed the migration guides. The application does work when deployed, but we have the need to generate the proxies now for added functionality, which does fail.

I'm not sure what that stackoverflow thread is trying to tell me.

Showing 31 to 40 of 71 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on December 08, 2025, 08:24
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.