How do you call a Web API endpoint without using JavaScript?

How do you call a Web API endpoint without using JavaScript? - title

Ever had to call an API from your MVC app? A lot of the time you can use JavaScript. But there are times when the client-side approach just doesn't cut it. Maybe your app needs to use the API as if it were a database, or you’re calling a public API. Chances are you need to transform the data somehow before it gets anywhere near the browser. Looks like you’ll have to call the API from your C# code. Sounds simple enough, right? Trouble is, you can’t seem to find any examples showing how to do this. You know how to do it using jQuery via a simple AJAX call. Can you do it in C# though?

HttpClient to the rescue

The good news is that you can and it’s quite straightforward. HttpClient exists for just this kind of scenario. In this post we’ll look at how to call a WebAPI Controller endpoint from MVC. By default, WebAPI Controller actions return JSON. So when you call them you get back a big string. You then parse this string into an object inside your MVC application and you're good to go. Let’s see this in action.

Bonus: To help you get started, we've created a Visual Studio solution for you to download, plus all you need to create a Nuget package for it.

In our scenario we've got a simple WebAPI Controller that returns a product by its id. The JSON returned looks something like this:


{"ProductId":3,"Name":"Product 3","Description":"Description 3","CreatedOn":"2015-11-13T17:01:18.6953449+00:00"}

Let's start by creating an ApiClient that we can call to hit any API and return the result. We'll then create a specific product client that uses the ApiClient. It will hit the product API controller and return a ProductApiModel. Here’s the ApiClient:


public interface IApiClient
{
    Task<HttpResponseMessage> GetFormEncodedContent(string requestUri, params KeyValuePair<string, string>[] values);
}

public class ApiClient : IApiClient
{
    private const string BaseUri = "Http://localhost:28601/";

    public async Task<HttpResponseMessage> GetFormEncodedContent(string requestUri, params KeyValuePair<string, string>[] values)
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(BaseUri);
            using (var content = new FormUrlEncodedContent(values))
            {
                var query = await content.ReadAsStringAsync();
                var requestUriWithQuery = string.Concat(requestUri, "?", query);
                var response = await client.GetAsync(requestUriWithQuery);
                return response;
            }
        }
    }
}

Both FormEncodedContent and HttpClient expose async methods only, so the calls are both awaitable. First of all we encode the parameters we’re passing across. We then retrieve the JSON data from the API as a string.

Data Classes

Now it’s time to turn that into an ApiModel object. Before we do that, let's have a look at the data classes we'll be using:


public abstract class ApiResponse
{
    public bool StatusIsSuccessful { get; set; }
    public HttpStatusCode ResponseCode { get; set; }
    public string ResponseResult { get; set; }
}

public abstract class ApiResponse<T> : ApiResponse
{
    public T Data { get; set; }
}

public class ProductApiModel
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class ProductResponse : ApiResponse<ProductApiModel>
{
}

The Product Client

And now the product client itself. We're introducing a base class here too with methods for decoding the JSON. This also allows us to hide the ApiClient from any calling code:


public interface IProductClient
{
    Task<ProductResponse> GetProduct(int productId);
}

public class ProductClient : ClientBase, IProductClient
{
    private const string ProductUri = "api/product";

    public ProductClient(IApiClient apiClient) : base(apiClient)
    {
    }

    public async Task<ProductResponse> GetProduct(int productId)
    {
        var idPair = new KeyValuePair<string, string>("id", productId.ToString());
        return await GetJsonDecodedContent<ProductResponse, ProductApiModel>(ProductUri, idPair);
    }
}

public abstract class ClientBase
{
    private readonly IApiClient apiClient;

    protected ClientBase(IApiClient apiClient)
    {
        this.apiClient = apiClient;
    }

    protected async Task<TResponse> GetJsonDecodedContent<TResponse, TContentResponse>(string uri, params KeyValuePair<string, string>[] requestParameters) where TResponse : ApiResponse<TContentResponse>, new()
    {
        var apiResponse = await apiClient.GetFormEncodedContent(uri, requestParameters);
        var response = await CreateJsonResponse<TResponse>(apiResponse);
        response.Data = Json.Decode<TContentResponse>(response.ResponseResult);
        return response;
    }

    private static async Task<TResponse> CreateJsonResponse<TResponse>(HttpResponseMessage response) where TResponse : ApiResponse, new()
    {
        var clientResponse = new TResponse
        {
            StatusIsSuccessful = response.IsSuccessStatusCode,
            ResponseCode = response.StatusCode
        };
        if (response.Content != null)
        {
            clientResponse.ResponseResult = await response.Content.ReadAsStringAsync();
        }

        return clientResponse;
    }
}

How do we call this?

The last thing to do is see how we could call this from an MVC controller (or anywhere else). Because our API call is asynchronous, the MVC Controller action must be asynchronous too.


public class ProductController : Controller
{
    private readonly IProductClient productClient;

    public HomeController(IProductClient productClient)
    {
        this.productClient = productClient;
    }

    public async Task<ActionResult> GetProduct(int id)
    {
        var product = await productClient.GetProduct(id);
        var model = // Create ViewModel via some kind of mapping (check the accompanying VS solution to see this in action)
        return View(model);
    }
}

Wrapping up

We covered a fair bit in this article. Let's recap:

  • We created an ApiClient to call out to an API endpoint
  • We wrapped that call in a ProductClient that called out to a specific endpoint to return a product
  • We parsed the JSON string from the API into a ProductApiModel within our domain
  • We hooked all of this up within an async Controller action in our MVC code
Bonus: Download the Visual Studio solution and create a Nuget package to use whenever you need to call a WebAPI endpoint from MVC.