I have an n-tier application, whereas the core web service is built with Web API. many of the web service's methods are set as HTTPGET and accept a DTO object as parameter. my client app, built with MVC 5 is using HttpClient to call this API.
so it seems that by using client.PostAsJsonAsync() I can pass an object, whereas client.GetAsync() doesn't allow me to do that. this forces me to explicitly specify the properties of DTO in the URL, which works, but seem a bit redundant.
Can somebody explain why this is not possible through a GET call and suggest a better practice?
Why does passing data in the URI seem redundant? The HTTP spec says that GET methods are not to use content sent in the body. This is primarily to facilitate caches being able to cache responses based only on the URI, method and headers. Requiring caches to parse the body of a message to identify a resource would be very inefficient.
Here is an basic extension method that will do the grunt work for you,
public static class UriExtensions
{
public static Uri AddToQuery<T>(this Uri requestUri, T dto)
{
Type t = typeof(T);
var properties = t.GetProperties();
var dictionary = properties.ToDictionary(
info => info.Name, info => info.GetValue(dto, null).ToString());
var formContent = new FormUrlEncodedContent(dictionary);
var uriBuilder = new UriBuilder(
requestUri) { Query = formContent.ReadAsStringAsync().Result };
return uriBuilder.Uri;
}
}
and assuming you have a DTO like this,
public class Foo
{
public string Bar { get; set; }
public int Baz { get; set; }
}
you can use it like this.
[Fact]
public void
Foo()
{
var foo = new Foo() { Bar = "hello world", Baz = 10 };
var uri = new Uri("http://example.org/blah");
var uri2 = uri.AddToQuery(foo);
Assert.Equal("http://example.org/blah?Bar=hello+world&Baz=10",
uri2.AbsoluteUri);
}