Michael Winther
Michael Winther

Reputation: 381

How to send a complex object using Get with c# HttpClient

I have a c# project and looking to make use of an api. The documentation is here if interested: link

When I want to have a list of all "Customers" from the api, which has some required properties:

attention.self, currency, customerContact.self, customerGroup, customerGroup.self, defaultDeliveryLocation.self, invoices.self, layout.self, name, paymentTerms, paymentTerms.self, salesPerson.self, self, templates.self, totals.self, vatZone, vatZone.self

I have a custom object which is identical in naming as the required properties. The object is complex as it have references to objects like "attention, customerContact, customerGroup, paymentTerms.." just like the documentation states.

Now the endpoint I have to use is "\customers" with a Get, so I have to parameterize the properties.

I have searched for a solution to convert a complex object into a uri like "?name=Mike&currency=USD&..", but unfortunately I only found a solution which could make a custom object with only simple types to a formatted parameter string.

So I gave up and tried to write my own hardcoded url string for now, but how do I get complex objects into the url query, like "attention.self"?

Would "?attention.self=Something&.." make the api translate it so that it knows "attention" is another object and "self" is a property on that?

And any advice on how to do this more optimized would be great.

Upvotes: 2

Views: 873

Answers (1)

Ashkan Mobayen Khiabani
Ashkan Mobayen Khiabani

Reputation: 34180

You can use Reflection:

public IEnumerable<string> ToQueryStringItem<T>(T entity)
{
     foreach(var pi in typeof(T).GetProperties())
         yield return $"{pi.Name}={pi.GetValue(entity)}";
}

public IEnumerable<string> ToQueryString<T>(T entity)
     => $"?{string.Join("&", ToQueryString(entity).ToList())}";

now simply you can do it like:

string qs = ToQueryString(someClassInstance);

Please note that if the class properties are not of primitive types, you will need a more complex code for reflection.

And also if you want some customized values it will also be doable, for instance lets say instead of true and false, you want 1 and 0:

foreach(var pi in typeof(T).GetProperties())
{
     switch(pi.PropertyType.ToString())
     {
          case "Boolean":
               yield return $"{pi.Name}={(pi.GetValue(entity)?1:0)};
          //....
          default:
               yield return $"{pi.Name}={pi.GetValue(entity)}";   
     }
}

You may also want to hide some properties from being used in query string, for that you can create an attribute:

public class IgnoreInQueryStringAttribute: Attribute {}

and use it for any property you don't want to be in the query string:

public class Customer
{
     [IgnoreInQueryString]
     public int Id { get; set; }
     public string Firstname { get; set; } 
}

and then:

foreach(var pi in typeof(T).GetProperties())
{
    if(pi.GetCustomAttributes(typeof(IgnoreInQueryString), false).Length == 0)     
    {
         //....
    }
}

Upvotes: 3

Related Questions