Generated code missing nested type in IReturn

I’m sure this is related to how I’m implementing my return type. I have a generic ListResponse class that has a List Items property where I have my data. In fact, all of my responses have a wrapper class. SingleResponse, ListResponse, etc. The AssetAllocationDto class doesn’t get addressed when generating code from metadata or from ui.

[Api("Gets your asset allocations")]
[Description("Description of the API")]
[Notes("Full <strong>html-enabled</strong> notes about the API")]
[Route("/assets/allocations", HttpMethods.Get)]
public class GetAssetAllocations : RequestBase, IGet, IReturn<ListResponse<AssetAllocationDto>>
{
}

Please provide the class definitions of all DTO types so we can repro the issue locally.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using ServiceStack;
using ServiceStack.DataAnnotations;
using Wdp.ServiceModels;
using Wdp.ServiceModels.Assets;

namespace Wdp.ServiceModels
{
    public interface IHasEtag
    {
        string Etag { get; set; }
    }

    public interface IHasResponseStatus
    {
        ResponseStatus ResponseStatus { get; set; }
    }

    public interface IHasSeconds
    {
        double? Seconds { get; set; }
    }

    public interface IHasSecurityContextToken
    {
        string Token { get; set; }
    }

    public interface IResponse
        : IHasResponseStatus, IHasSeconds, IHasVersion
    {
    }

    public interface IResponseWithEtag
        : IResponse, IHasEtag
    {
    }

    public class ListResponse<T>
        : ResponseBase
    {
        public ListResponse()
        {
            Items = new List<T>{};
        }

        public List<T> Items { get; set; }
    }

    public class RequestBase
        : IHasSecurityContextToken, IHasVersion
    {
        [Input(Placeholder="If not set, defaults to bearer or basic auth username.", Type="textarea")]
        public string Token { get; set; }

        [Input(Placeholder="If not set, defaults to latest", Type="number")]
        public int Version { get; set; }
    }

    public class ResponseBase
        : IResponseWithEtag
    {
        public int Version { get; set; }
        public string Etag { get; set; }
        public double? Seconds { get; set; }
        public ResponseStatus ResponseStatus { get; set; }
    }

}

namespace Wdp.ServiceModels.Assets
{
    ///<summary>
    ///Gets your asset allocations
    ///</summary>
    [Route("/assets/allocations", "GET")]
    [Api(Description="Gets your asset allocations")]
    public class GetAssetAllocations
        : RequestBase, IReturn<ListResponse<AssetAllocationDto>>, IGet
    {
    }

}

And what’s missing from that:

public class AssetAllocationDto
{
    public string AssetClass { get; set; } = default!;
    public double MarketValue { get; set; } = default!;
}

It’s including the AssetAllocationDto in the generated types here, can you provide a stand-alone repro that contains the issue, e.g. from an empty web template:

$ x new web Test

@mythz attached is a sample project demonstrating the issue. https://drive.google.com/file/d/1qFuRmJqwugWEKiV1xuGDq8XyKnJSIIc3/view?usp=sharing

This demo is generating AssetAllocationDto, here’s the full code-gen from https://localhost:5001/types/csharp:

/* Options:
Date: 2022-08-17 10:45:33
Version: 6.21
Tip: To override a DTO option, remove "//" prefix before updating
BaseUrl: https://localhost:5001

//GlobalNamespace: 
//MakePartial: True
//MakeVirtual: True
//MakeInternal: False
//MakeDataContractsExtensible: False
//AddReturnMarker: True
//AddDescriptionAsComments: True
//AddDataContractAttributes: False
//AddIndexesToDataMembers: False
//AddGeneratedCodeAttributes: False
//AddResponseStatus: False
//AddImplicitVersion: 
//InitializeCollections: True
//ExportValueTypes: False
//IncludeTypes: 
//ExcludeTypes: 
//AddNamespaces: 
//AddDefaultXmlNamespace: http://schemas.servicestack.net/types
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using ServiceStack;
using ServiceStack.DataAnnotations;
using Wdp.ServiceModels;
using Wdp.ServiceModels.Assets;
using Test.ServiceModel;

namespace Test.ServiceModel
{
    [Route("/hello")]
    [Route("/hello/{Name}")]
    public partial class Hello
        : IReturn<HelloResponse>
    {
        public virtual string Name { get; set; }
    }

    public partial class HelloResponse
    {
        public virtual string Result { get; set; }
    }

}

namespace Wdp.ServiceModels
{
    public partial interface IHasEtag
    {
        string Etag { get; set; }
    }

    public partial interface IHasResponseStatus
    {
        ResponseStatus ResponseStatus { get; set; }
    }

    public partial interface IHasSeconds
    {
        double? Seconds { get; set; }
    }

    public partial interface IHasSecurityContextToken
    {
        string Token { get; set; }
    }

    public partial interface IResponse
        : IHasResponseStatus, IHasSeconds, IHasVersion
    {
    }

    public partial interface IResponseWithEtag
        : IResponse, IHasEtag
    {
    }

    public partial class ListResponse<T>
        : ResponseBase
    {
        public ListResponse()
        {
            Items = new List<T>{};
        }

        public virtual List<T> Items { get; set; }
    }

    public partial class RequestBase
        : IHasSecurityContextToken, IHasVersion
    {
        [Input(Placeholder="If not set, defaults to bearer or basic auth username.", Type="textarea")]
        public virtual string Token { get; set; }

        [Input(Placeholder="If not set, defaults to latest", Type="number")]
        public virtual int Version { get; set; }
    }

    public partial class ResponseBase
        : IResponseWithEtag
    {
        public virtual int Version { get; set; }
        public virtual string Etag { get; set; }
        public virtual double? Seconds { get; set; }
        public virtual ResponseStatus ResponseStatus { get; set; }
    }

}

namespace Wdp.ServiceModels.Assets
{
    public partial class AssetAllocationDto
    {
        public virtual string ProductStyle { get; set; }
        public virtual double MarketValue { get; set; }
    }

    public partial class AssetByProductDto
    {
        public virtual string ProductName { get; set; }
        public virtual string ProductTicker { get; set; }
        public virtual double MarketValuePercentage { get; set; }
        public virtual double MarketValue { get; set; }
    }

    public partial class AssetByProductManagerDto
    {
        public virtual string ProductManager { get; set; }
        public virtual double MarketValue { get; set; }
    }

    public partial class AssetByProductTypeDto
    {
        public virtual string ProductType { get; set; }
        public virtual double MarketValue { get; set; }
    }

    public partial class AssetByRegistrationTypeDto
    {
        public virtual string RegistrationType { get; set; }
        public virtual double HeldMarketValue { get; set; }
        public virtual double HeldAwayMarketValue { get; set; }
    }

    ///<summary>
    ///Gets your asset allocations
    ///</summary>
    [Route("/assets/allocations", "GET")]
    [Route("/assets/market-value/by-product-style", "GET")]
    [Api(Description="Gets your asset allocations")]
    public partial class GetAssetAllocations
        : RequestBase, IReturn<ListResponse<AssetAllocationDto>>, IGet
    {
    }

    ///<summary>
    ///Concentration of individual and packaged products/portfolios
    ///</summary>
    [Route("/assets/market-value/by-product", "GET")]
    [Api(Description="Concentration of individual and packaged products/portfolios")]
    public partial class GetAssetsByProduct
        : RequestBase, IReturn<ListResponse<AssetByProductDto>>, IGet
    {
        public virtual int Count { get; set; }
    }

    ///<summary>
    ///Concentration of investment managers
    ///</summary>
    [Route("/assets/market-value/by-product-manager", "GET")]
    [Api(Description="Concentration of investment managers")]
    public partial class GetAssetsByProductManager
        : RequestBase, IReturn<ListResponse<AssetByProductManagerDto>>, IGet
    {
    }

    ///<summary>
    ///Provides time series trend by line of business
    ///</summary>
    [Route("/assets/market-value/by-product-type", "GET")]
    [Api(Description="Provides time series trend by line of business")]
    public partial class GetAssetsByProductType
        : RequestBase, IReturn<ListResponse<AssetByProductTypeDto>>, IGet
    {
    }

    ///<summary>
    ///Gets your asset by registration type (held vs held away)
    ///</summary>
    [Route("/assets/market-value/by-registration-type", "GET")]
    [Api(Description="Gets your asset by registration type (held vs held away)")]
    public partial class GetAssetsByRegistrationType
        : RequestBase, IReturn<ListResponse<AssetByRegistrationTypeDto>>, IGet
    {
    }

}

It’s on these pages where it’s missing:

The pages that list partial results per type. But you’re right – on the overall types pages, they’re there.

Thanks for the repro, this should now be resolved from v6.2.1+ that’s now available on MyGet.

1 Like