Base solution for your next web application
Open Closed

RAD Tool: nswag goes in Exception with "Cyclic references detected." reason #6920


User avatar
0
simplexsrl created

As per subject, trying to update service-proxies.ts with nswag tool, this raises System.InvalidOperationException: Cyclic references detected.

Some entity had the same navigation property to the same entity ... e.g. EntityA had a relation with EntityC and EntityB has the same relation with EntityB.

using RAD tool we have EntityC's LookupTableDto duplicated in EntityA and EntityB namespaces.

This scenario raised an exception to Swagger in .net, that we resolved setting it to use FullName as CustomSchemaIds options.CustomSchemaIds(x => x.FullName);

Any idea on how to avoid Cyclic exception and continue to use RAD tool?


12 Answer(s)
  • User Avatar
    0
    yekalkan created

    You can remove one of the duplicated dtos and use the other one as common.

  • User Avatar
    0
    simplexsrl created

    Yes of course, but in this way everytime we use RAD tool in similar situations, we have to apply this workaround! This is less helpful, imho!

    Is possible to have RAD tool sources, to find a definitive solution more useful than a simple workaround?

  • User Avatar
    0
    yekalkan created

    Yes of course, but in this way everytime we use RAD tool in similar situations, we have to apply this workaround!

    What i've suggested is not a workaround, it is what need to be done. if you didn't and are not going to modify any of the duplicated dtos, you can use one of them as common. I don't think this is a hard process. Rad tool doesn't handle this process itself because we don't want to rely on existing code even it is created by rad tool in past.

  • User Avatar
    0
    simplexsrl created

    Thanks for your explanation, but honestly, I disagree with your point of view.

    RAD tool is a Rapid Development tool that should avoid users to perform annoying and consuming time manual operations like creating entities, dtos, application services and - most valuable task - writing Angular's code. Obviously, this is true for those entities that are simple and for an initial development step.

    In a LOB application, could be very frequent to have entities that relate to each other... and could happen - frequently too - to add new properties.

    In that case, RAD is a very killer technology! If the entity doesn't have any customization (in AppService or in UI) with a bunch of seconds app is updated and ready to use newly fields!

    Backing to the original problem, even if I remove duplicated class, every time I need to re-execute RAD tool, I have to remove all of the duplicated class to successfully build. This not represent a hard process, if involved entities are a few.

    In addition, from a Code Quality point-of-view, is preferable to avoid unused class or interface or others because could be difficult to remember for future implementations!

    A possible solution should be to avoid the creation of the LookupTableDto class (in that case) if it is already present in ForeignEntity's DTOs folder, those could respect your requirement to don't rely on existing code ... RAD should perform only a File.Exists check!

    Lastly, my suggestion is to improve RAD tool using specific comments (like //RAD AUTOGENERATED CODE) to identify which files have been generated from itself and - in that way - should modify them safely!

    Many thanks.

  • User Avatar
    0
    yekalkan created

    Thanks for your suggestions.

    What is your rad tool version? We've made some changes on that issue in v1.8.3.

  • User Avatar
    0
    simplexsrl created

    Currently I'm using embedded AspNetZeroRadTool.dll, which solution was downloaded last week, from macOS.

    How can I check which version it is?

  • User Avatar
    0
    yekalkan created

    You can copy AspNetZeroRadTool.dll to your solution to be sure you get the v1.8.3.1 version.

    https://github.com/aspnetzero/aspnet-zero-core/tree/dev/aspnet-core/AspNetZeroRadTool

  • User Avatar
    0
    simplexsrl created

    I'll give it a try, meanwhile ... is there any possibility - or plans - to use RAD Tool for generate Server-Side or Angular files only?

    Imagine a scenario where you customized DTOs in a particular way that doesn't affect entities, and want to regenerate UI files

    UPDATE I just tried latest AspNetZeroRadTool dlls and goes in warning without generating files. Following are definition file and an extract of output execution.

    {
        "MenuPosition": "main",
        "RelativeNamespace": "Common.Directory.DirectoryItems",
        "EntityName": "Company",
        "EntityNamePlural": "Companies",
        "TableName": "Common_DirectoryItems",
        "PrimaryKeyType": "long",
        "BaseClass": "DirectoryItem",
        "AutoMigration": false,
        "UpdateDatabase": false,
        "CreateUserInterface": true,
        "CreateViewOnly": true,
        "PagePermission": {
            "Host": true,
            "Tenant": true
        },
        "Properties": [
            {
                "Name": "DisplayName",
                "Type": "string",
                "MaxLength":255,
                "MinLength":1,
                "Range": {
                    "IsRangeSet": false,
                    "MinimumValue": 0,
                    "MaximumValue": 0
                },
                "Required": true,
                "Nullable": false,
                "Regex": "",
                "UserInterface": {
                    "List": true,
                    "AdvancedFilter": true,
                    "CreateOrUpdate": true
                }
            },
            
            {
                "Name": "Sdi",
                "Type": "string",
                "MaxLength":7,
                "MinLength":7,
                "Range": {
                    "IsRangeSet": false,
                    "MinimumValue": 0,
                    "MaximumValue": 0
                },
                "Required": false,
                "Nullable": true,
                "Regex": "",
                "UserInterface": {
                    "List": true,
                    "AdvancedFilter": true,
                    "CreateOrUpdate": true
                }
            },
    
            {
                "Name": "UseSdi",
                "Type": "bool",
                "MaxLength":0,
                "MinLength":0,
                "Range": {
                    "IsRangeSet": false,
                    "MinimumValue": 0,
                    "MaximumValue": 0
                },
                "Required": true,
                "Nullable": false,
                "Regex": "",
                "UserInterface": {
                    "List": true,
                    "AdvancedFilter": true,
                    "CreateOrUpdate": true
                }
            },
            {
                "Name": "PaymentTerms",
                "Type": "int",
                "MaxLength":0,
                "MinLength":0,
                "Range": {
                    "IsRangeSet": false,
                    "MinimumValue": 0,
                    "MaximumValue": 0
                },
                "Required": false,
                "Nullable": true,
                "Regex": "",
                "UserInterface": {
                    "List": true,
                    "AdvancedFilter": true,
                    "CreateOrUpdate": true
                }
            },
            {
                "Name": "PaymentTermsType",
                "Type": "PaymentTermsType",
                "MaxLength":0,
                "MinLength":0,
                "Range": {
                    "IsRangeSet": false,
                    "MinimumValue": 0,
                    "MaximumValue": 0
                },
                "Required": false,
                "Nullable": true,
                "Regex": "",
                "UserInterface": {
                    "List": true,
                    "AdvancedFilter": true,
                    "CreateOrUpdate": true
                }
            }
        ],
        "NavigationProperties": [
            {
                "Namespace": "SmartPortal.Common.Directory.CompanyTypes",
                "ForeignEntityName": "CompanyType",
                "IdType": "int",
                "IsNullable": false,
                "PropertyName": "CompanyTypeId",
                "DisplayPropertyName": "Name",
                "DuplicationNumber": 0,
                "RelationType": "single"
            },
            {
                "Namespace": "SmartPortal.Common",
                "ForeignEntityName": "Vat",
                "IdType": "int",
                "IsNullable": true,
                "PropertyName": "VatId",
                "DisplayPropertyName": "Name",
                "DuplicationNumber": 0,
                "RelationType": "single"
            }
            
        ],
        "EnumDefinitions": [
            {
                "Namespace": "SmartPortal.Common",
                "Name": "PaymentTerms",
                "EnumProperties": [
                    {
                        "Name": "GG",
                        "Value": 1
                    },
                    {
                        "Name": "FMDF",
                        "Value": 2
                    }
                ]
            }
        ]
    }
    
  • User Avatar
    0
    simplexsrl created

    EXECUTION OUTPUT

    fncap$ dotnet AspNetZeroRadTool.dll ../../RAD/Common/Directory/Company.json 
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\ICompaniesAppService.cs is being generated.
    -> SmartPortal.Application\Common\Directory\DirectoryItems\Exporting\CompaniesExcelExporter.cs is being generated.
    -> SmartPortal.Core\Common\Directory\DirectoryItems\Company.cs is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> SmartPortal.Application\Common\Directory\DirectoryItems\Exporting\ICompaniesExcelExporter.cs is being generated.
    -> SmartPortal.Application\Common\Directory\DirectoryItems\CompaniesAppService.cs is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> SmartPortal.Core.Shared\Common\Directory\DirectoryItems\CompanyConsts.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\GetAllForLookupTableInput.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\CompanyCompanyTypeLookupTableDto.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\CompanyVatLookupTableDto.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\CreateOrEditCompanyDto.cs is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\GetCompanyForViewDto.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\GetAllCompaniesInput.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\GetAllCompaniesForExcelInput.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\GetCompanyForEditOutput.cs is being generated.
    -> SmartPortal.Application.Shared\Common\Directory\DirectoryItems\Dtos\CompanyDto.cs is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> \..\src\SmartPortal.Core\Authorization\AppPermissions.cs is being modified.
    -> \..\src\SmartPortal.Core\Authorization\AppAuthorizationProvider.cs is being modified.
    -> \..\src\SmartPortal.EntityFrameworkCore\EntityFrameworkCore\SmartPortalDbContext.cs is being modified.
    -> \..\src\SmartPortal.Application\CustomDtoMapper.cs is being modified.
    -> app\main\directoryItems\companies\companyType-lookup-table-modal.component.less is being generated.
    -> app\main\directoryItems\companies\vat-lookup-table-modal.component.less is being generated.
    -> app\main\directoryItems\companies\companyType-lookup-table-modal.component.ts is being generated.
    -> app\main\directoryItems\companies\vat-lookup-table-modal.component.ts is being generated.
    -> app\main\directoryItems\companies\companyType-lookup-table-modal.component.html is being generated.
    -> app\main\directoryItems\companies\vat-lookup-table-modal.component.html is being generated.
    -> app\main\directoryItems\companies\view-company-modal.component.ts is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> app\main\directoryItems\companies\companies.component.ts is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> app\main\directoryItems\companies\companies.component.html is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> app\main\directoryItems\companies\view-company-modal.component.html is being generated.
    -> app\main\directoryItems\companies\create-or-edit-company-modal.component.html is being generated.
    Warning: System.Exception: Word can not be null. exiting...
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Lower(String word)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.bMbeb0mwZ4cnxO8WMkM(Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.ReplaceAlsoWithLowerCase(Object template, Object placeholder, Object value)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.XvOj3pBU9PRrU6bUaR6(Object , Object , Object )
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.PlaceholderReplacer.Replace(String template, EntityConfiguration entity, Property property, EnumDefinition enumDefinition, NavigationProperty navigationProperty)
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.SetEnums()
       at AspNetZeroRadTool.FileWizards.FileGenerators.Generic.GenericFileContentGenerator.GenerateAndGetContent()
       at AspNetZeroRadTool.GeneratorFromTemplate.NPlmurbr8sqIqPi48dS(Object )
       at AspNetZeroRadTool.GeneratorFromTemplate.FileGeneratorBasedOnEntity(Object templateInfo, Object templatePathInfo, Object targetFolderRoot, Object entity)
    -> app\main\directoryItems\companies\create-or-edit-company-modal.component.ts is being generated.
    -> \..\..\angular\src\app\main\main.module.ts is being modified.
    -> \..\..\angular\src\app\main\main-routing.module.ts is being modified.
    -> \..\..\angular\src\app\shared\layout\nav\app-navigation.service.ts is being modified.
    -> \..\..\angular\src\shared\service-proxies\service-proxy.module.ts is being modified.
    -> \..\src\SmartPortal.Core\Localization\SmartPortal\SmartPortal.xml is being modified.
    
    Code generation is complete. Press ENTER to exit...
    
  • User Avatar
    0
    yekalkan created

    Hi,

    There are some missing fields in you json file (new features).

    See commit below

  • User Avatar
    0
    simplexsrl created

    Many Thanks! I'll fix them and retry!

    Another question - that I made before and in slack's chat too - I'm in a situation where I generated entities with tool and after customized them for implementing TPH. Some manual work to do, but not so much complicated.

    What is "complicated", therfor, is an evenutally regeneration of Angular's file only (or .NET files too).

    Imagine a scenario where entities and DTOs doesn't reflect a 1:1 relation, some DTO properties could be custom mapped to entities properties with AutoMapper or viceversa.

    In that case, I'd like to use tool for regenerate only Angular's files, or .NET file with an argument passed in command line, or better solution could be what I suggested before ... using some special comment to identify tool's generated file, and if those comments are removed, file will leave intact as-is.

    Many thanks for yuor attention and your great job!

  • User Avatar
    0
    yekalkan created

    You can set "CreateUserInterface" as false in entity json file if you don't want any changes in angular side. However, we don't provide a way to skip generating server side codes. We can evaluate your idea.

    For now, i can only suggest an easy but dirty workaround to skip generating server side codes: open "AspNetZeroRadTool\config.json" file and set a fake path for "CoreSrcPath" field. (Remember to set it back after code generation.)