swagger-api / swagger-api/swagger-codegen

[CSharp] ASP.NET Core [FromQuery] parameter doesn't follow the DataMember attributes with classes

Open
#10,180 0 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

I have a simple request class with DataContract and DataMember attributes specified:

[DataContract(Name = "getOrdersRequest")]
    public class GetOrdiniRequest
    {
        [DataMember(Name = "id")]
        public int? Id { get; set; }
        [DataMember(Name = "plant")]
        public string Stabilimento { get; set; }
        [DataMember(Name = "warehouse")]
        public string Magazzino { get; set; }
        [DataMember(Name = "group")]
        public string Raggruppamento { get; set; }
        [DataMember(Name = "orderType")]
        public string TipoOrdine { get; set; }
        [DataMember(Name = "orderYear")]
        public int? AnnoOrdine { get; set; }
        [DataMember(Name = "orderNumber")]
        public string NumeOrdine { get; set; }
        [DataMember(Name = "paging")]
        public PagingParameters Paging { get; set; }
    }

In an ASP.NET web api controller I have this type of method with that class as a parameter (pay attention at the FromQuery attribute):

[HttpGet()]
[ProducesResponseType(200)]
public Task<ActionResult<IEnumerable<OrdineTestataDto>>> GetOrdiniAsync([FromQuery] GetOrdiniRequest request) =>
{
    ...body method...
}

The client code generated from this method doesn't follow the DataMember attributes, so every parameter in the code generated have the name of the original property.

Example: "Stabilimento" should be "plant"

Swagger version

Assembly NSwag.AspNetCore, Version=13.2.3.0

Swagger declaration file content or url
public async System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<OrdineTestataDto>> GetOrdiniAsync(
    int? id = null, string stabilimento = null, string magazzino = null, 
    string raggruppamento = null, string tipoOrdine = null, 
    int? annoOrdine = null, string numeOrdine = null, 
    int? paging_PageNumber = null, int? paging_PageSize = null, 
    int? paging_Skip = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
        {
            var urlBuilder_ = new System.Text.StringBuilder();
            urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Orders?");
            if (id != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Id") + "=").Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (stabilimento != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Stabilimento") + "=").Append(System.Uri.EscapeDataString(ConvertToString(stabilimento, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (magazzino != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Magazzino") + "=").Append(System.Uri.EscapeDataString(ConvertToString(magazzino, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (raggruppamento != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Raggruppamento") + "=").Append(System.Uri.EscapeDataString(ConvertToString(raggruppamento, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (tipoOrdine != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("TipoOrdine") + "=").Append(System.Uri.EscapeDataString(ConvertToString(tipoOrdine, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (annoOrdine != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("AnnoOrdine") + "=").Append(System.Uri.EscapeDataString(ConvertToString(annoOrdine, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (numeOrdine != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("NumeOrdine") + "=").Append(System.Uri.EscapeDataString(ConvertToString(numeOrdine, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (paging_PageNumber != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Paging.PageNumber") + "=").Append(System.Uri.EscapeDataString(ConvertToString(paging_PageNumber, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (paging_PageSize != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Paging.PageSize") + "=").Append(System.Uri.EscapeDataString(ConvertToString(paging_PageSize, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            if (paging_Skip != null) 
            {
                urlBuilder_.Append(System.Uri.EscapeDataString("Paging.Skip") + "=").Append(System.Uri.EscapeDataString(ConvertToString(paging_Skip, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
            }
            urlBuilder_.Length--;
    
            var client_ = _httpClient;
            try
            {
                using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false))
                {
                    request_.Method = new System.Net.Http.HttpMethod("GET");
                    request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
    
                    PrepareRequest(client_, request_, urlBuilder_);
                    var url_ = urlBuilder_.ToString();
                    request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
                    PrepareRequest(client_, request_, url_);
    
                    var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
                    try
                    {
                        var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
                        if (response_.Content != null && response_.Content.Headers != null)
                        {
                            foreach (var item_ in response_.Content.Headers)
                                headers_[item_.Key] = item_.Value;
                        }
    
                        ProcessResponse(client_, response_);
    
                        var status_ = ((int)response_.StatusCode).ToString();
                        if (status_ == "200") 
                        {
                            var objectResponse_ = await ReadObjectResponseAsync<System.Collections.Generic.IEnumerable<OrdineTestataDto>>(response_, headers_).ConfigureAwait(false);
                            return objectResponse_.Object;
                        }
                        else
                        if (status_ != "200" && status_ != "204")
                        {
                            var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 
                            throw new WebApiException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null);
                        }
            
                        return default(System.Collections.Generic.IEnumerable<OrdineTestataDto>);
                    }
                    finally
                    {
                        if (response_ != null)
                            response_.Dispose();
                    }
                }
            }
            finally
            {
            }
        }
Suggest a fix/enhancement

Every parameters should follow the data member attribute

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the ASP.NET Core [FromQuery] parameter handling and the generated C# client shown in the report. Check how DataMember names are represented for query parameters, including nested Paging fields. Done means the generated request uses names such as "plant" instead of "Stabilimento" while preserving the other query parameters.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.