How to create a class and pass an attribute value in the class constructor in C#

Asked

Viewed 141 times

2

Hello, I’m making an integration with the Tray Comerce API and thought to generate a generic class with the response of lists. In all listings, the API implements the following return class:

public class Response<T>
{
    [JsonProperty("paging")]
    public ResponsePaging Paging { get; set; }

    [JsonProperty("sort")]
    public Dictionary<string, string> Sort { get; set; }

    [JsonProperty("availableFilters")]
    public List<string> AvailableFilters { get; set; }

    [JsonProperty("appliedFilters")]
    public List<string> AppliedFilters { get; set; }

    [JsonProperty(????)]
    public List<T> List { get; set; }

    public class ResponsePaging
    {
        public int total { get; set; }
        public int page { get; set; }
        public int offset { get; set; }
        public int limit { get; set; }
        public int maxLimit { get; set; }
    }
}

The problem is that for each API route that makes a listing, the result of that listing is set to a different name (e.g. {web_api}/orders returns Orders, in {web_api}/products returns Products, etc....)

How do I pass as parameter to the class which will be the name of the property that will be assigned to [JsonProperty(????)] of property List<T> List?

  • 1

    I did some research and it looks like you might be able to replace DefaultContractResolver and implement its own mechanism to provide Propertyname (in JSON). https://stackoverflow.com/a/26883987/194717

  • I did my Contractresolver, I just don’t know how to implement it. Do you have any example? , I’m hunting here but just think how to create it..

2 answers

3

I was able to solve my problem based on what @Tony said in the comment and also in that fiddle I found. The answer was to generate a DefaultContractResolver customized with this specific treatment and a return method that applies this conversion. The solution was thus:

public class Response<A>
{
    private JsonSerializerSettings settings { get; set; }

    public Response(string listName)
    {
        settings = new JsonSerializerSettings
        {
            ContractResolver = new ResponseContractResolver(listName),
            Formatting = Formatting.Indented
        };
    }

    public JsonResponse<A> deserializeObject(string json)
    {
        return JsonConvert.DeserializeObject<JsonResponse<A>>(json, settings);
    }

    public class ResponseContractResolver : DefaultContractResolver
    {
        private string ListName { get; set; }

        public ResponseContractResolver(string listName) => ListName = listName;

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
            list.Where(x => x.UnderlyingName == "List").First().PropertyName = ListName;
            return list;
        }
    }

    public class JsonResponse<B>
    {
        [JsonProperty("paging")]
        public ResponsePaging Paging { get; set; }

        [JsonProperty("sort")]
        public Dictionary<string, string> Sort { get; set; }

        [JsonProperty("availableFilters")]
        public List<string> AvailableFilters { get; set; }

        [JsonProperty("appliedFilters")]
        public List<string> AppliedFilters { get; set; }

        [JsonProperty("List")]
        public List<B> List { get; set; }

        public class ResponsePaging
        {
            [JsonProperty("total")]
            public int Total { get; set; }

            [JsonProperty("page")]
            public int Page { get; set; }

            [JsonProperty("Offset")]
            public int Offset { get; set; }

            [JsonProperty("Limit")]
            public int Limit { get; set; }

            [JsonProperty("MaxLimit")]
            public int MaxLimit { get; set; }
        }
    }

}

From this generic class, I just need to treat the return and tell you which name will return. So 1 only class "smart" and no gambiarra (né não @rovann-linhalis) solves the whole API response problem and reduces the code drastically, as in the example below:

class Foo 
{
    public int Id { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        // resposta em string json da api (mockup de exemplo)
        string jsonResponse = "{\"fooListTest\":[{\"Id\":1},{\"Id\":2},{\"Id\":4}]}";
        List<Foo> foos = new Response<Foo>("fooListTest").DeserializeObject(jsonResponse);
    }
}

1

The ideal would be an inheritance, so:

public class Response
{
    [JsonProperty("paging")]
    public ResponsePaging Paging { get; set; }

    [JsonProperty("sort")]
    public Dictionary<string, string> Sort { get; set; }

    [JsonProperty("availableFilters")]
    public List<string> AvailableFilters { get; set; }

    [JsonProperty("appliedFilters")]
    public List<string> AppliedFilters { get; set; }

    public class ResponsePaging
    {
        public int total { get; set; }
        public int page { get; set; }
        public int offset { get; set; }
        public int limit { get; set; }
        public int maxLimit { get; set; }
    }
}

public class ProductsResponse : Response
{
    [JsonProperty("products")]
    public List<Product> List { get; set; }
}

public class OrdersResponse : Response
{
    [JsonProperty("orders")]
    public List<Order> List { get; set; }
}

This way, when executing the request for Products, one expects a ProductsResponse and for requests, OrdersResponse

  • 1

    yes, I understand that if I make an inheritance I can solve the problem but if I had to implement new answers, I would have to at all times extend the Response class because of 1 reference. This would generate a "world" of classes that would be solved with only 1 generic

  • an alternative.... can be the famous gambiarra..... rsrs

  • I don’t think working with generic classes is a ploy. Mainly because I come from smart languages like Python and Javascript that don’t depend so much on the type...

  • 1

    No...I did not say generic classes.... I said that there is another method of gambiarra... but I did not put in the answer

  • 1

    a yes always has rsrs

Browser other questions tagged

You are not signed in. Login or sign up in order to post.