Invoke ASP.NET Web API using TypeScript and XMLHttpRequest
Invoking Web API is a quite common task in modern ASP.NET web applications.
Usually, developers resort to jQuery Ajax to call the Web API. If you are using
a client side framework such as Angular, you may also use the inbuilt ways to
make the Ajax calls. However, what if you aren't using these approaches? This
article discusses an alternative.
There are two aspects of this problem. Firstly, you wish to call an ASP.NET
Web API without using jQuery or any other framework. The solution to this
problem is to use XMLHttpRequest object of HTML5. The second aspect of the
problem is how to neatly organize the client side code that calls the Web API.
That's where TypeScript is going to help.
Do we need TypeScript for seemingly simple task of calling a Web API? Well,
that depends on the complexity of the application. If you are calling a simple
Web API and client side processing is minimum you may not use TypeScript at all.
However, TypeScript can be a good choice in the following situations:
- You want to neatly organize your client side code.
- You are using a same set of Web APIs at many places in your application.
- Your client side logic that involves Web API calls is quite complex and
lengthy.
- If you are already using TS in your application, you may wish to use
stick to OO style for the sake of consistency.
In this article we are going to use TypeScript and XMLHttpRequest to invoke
the Web API. Let's begin.
DbContext and Customer class
Create a new ASP.NET Web Application using Empty project template. Make sure
to check the MVC and Web API checkboxes while creating the project.

Then add a Entity Framework Code First model for the Customers table of
Northwind database. You add them to the Models folder. The Northwind DbContext
class and the Customer class is shown below:
public partial class Northwind : DbContext
{
public Northwind()
: base("name=Northwind")
{
}
public virtual DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating
(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>()
.Property(e => e.CustomerID)
.IsFixedLength();
}
}
public partial class Customer
{
[StringLength(5)]
public string CustomerID { get; set; }
[Required]
[StringLength(40)]
public string CompanyName { get; set; }
[StringLength(30)]
public string ContactName { get; set; }
[StringLength(15)]
public string Country { get; set; }
}
Note that the Customers table contains a few more columns than shown here.
For the sake of simplicity we use only CustomerID, CompanyName, ContactName and
Country.
Customer Web API controller
Now add a Web API controller and write the following code to it:
public class CustomerController : ApiController
{
public List<Customer> Get()
{
using (Northwind db = new Northwind())
{
return db.Customers.ToList();
}
}
public Customer Get(string id)
{
using (Northwind db = new Northwind())
{
return db.Customers.Find(id);
}
}
public string Post(Customer obj)
{
using (Northwind db = new Northwind())
{
db.Customers.Add(obj);
db.SaveChanges();
return "Customer added successfully!";
}
}
public string Put(string id, Customer obj)
{
using (Northwind db = new Northwind())
{
db.Entry(obj).State = EntityState.Modified;
db.SaveChanges();
return "Customer modified successfully!";
}
}
public string Delete(string id)
{
using (Northwind db = new Northwind())
{
db.Entry(db.Customers.Find(id)).State
= EntityState.Deleted;
db.SaveChanges();
return "Customer deleted successfully!";
}
}
}
We won't discuss this Web API class in detail here. It is suffice to mention
that it contains Get(), GetByID(), Post(), Put() and Delete() actions that
handle the corresponding HTTP verbs. These actions basically perform the CRUD
operations on the database.
Next, add HomeController and Index view. We don't have any specific UI as
such. However, for the sake of testing our TypeScript code we need the Index
view.
Ok. So far so good. Now it's time to shift our focus to TypeScript. If you
are using Visual Studio 2017 you already have TypeScript. If not, follow
this
link to grab the latest version of TypeScript.
Adding the TypeScript file and skeleton code
Now add Scripts folder to your project root. Then right click on it and add a
new TypeScript file named AjaxHelper.ts.

The AjaxHelper.ts file will define a module called AjaxHelper. The AjaxHelper
module will expose two classes - CustomerApiClient and CustoemrUI. Why do we
need two classes? If you look at the Web API calling code, you will realize that
there are two distinct concerns - invoking the API and updating the UI based on
the API outcome. We try to isolate these tasks in a separate classes for better
organization point of view. So, for one "ApiClient" class you can have one or
more "UI" classes depending on the pages and the UI.
The following code shows the skeleton of what goes inside the AjaxHelper.ts
file (so far).
module AjaxHelper {
export class CustomerApiClient {
}
export class CustomerUI {
}
}
Some auxiliaries
Before we go ahead and code the CustoemrApiClient class, let's add a couple
of things - an enumeration for specifying HTTP verbs and an interface for
defining the shape of Customer object that travels between the client and the
API. These two are shown below:
enum HttpVerbs {
GET, POST, PUT, DELETE
}
export interface ICustomer {
CustomerID: string;
CompanyName: string;
ContactName: string;
Country: string;
}
The HttpVerbs module has four possible values - GET, POST, PUT and DELETE.
The ICustomer interface specifies that every customer object should have
CustoemrID, CompanyName, ContactName and Country properties of type string.
CustomerApiClient class
Now, add a constructor to the CustomerApiClient class as shown below:
export class CustomerApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
}
Here, we declared a private variable - baseUrl - for storing the base address
of the Web API. This base address is assigned in the constructor of the
CustomerApiClient class.
Now, let's add a private helper method that will be called by other methods
of CustomerApiClient. This helper does the core job of invoking the Web API
using XMLHttpRequest object and is discussed next.
private callWebApi(url:string, verb:HttpVerbs,
data:ICustomer, callback):void {
let xhr = new XMLHttpRequest();
xhr.onload = function () {
let data = JSON.parse(xhr.responseText);
callback(data);
}
xhr.onerror = function () {
alert("Error while calling Web API");
}
let httpVerb: string;
switch (verb)
{
case HttpVerbs.GET:
httpVerb = "GET";
break;
case HttpVerbs.POST:
httpVerb = "POST";
break;
case HttpVerbs.PUT:
httpVerb = "PUT";
break;
case HttpVerbs.DELETE:
httpVerb = "DELETE";
break;
}
xhr.open(httpVerb, url);
xhr.setRequestHeader("Content-Type", "application/json");
if (data == null) {
xhr.send();
}
else {
xhr.send(JSON.stringify(data));
}
}
The callWebApi() method accepts four parameters - url, verb, data, and
callback. Their purpose is described below:
- The url parameter indicates the URL of the Web API. This URL is
different than the baseUrl private property in that the URL is baseUrl
appended with some extra details (CustomerID in this example).
- The verb parameter is of type HttpVerbs and is used to specify the HTTP
verb to be used for making the call to the Web API - GET, POST, PUT, or
DELETE.
- The data parameter is optional. When present it indicates an object that
is same in shape as defined by ICustomer interface.
- The callback parameter is a JavaScript function that is invoked upon
successful call to the Web API. This way we isolate the Web API calling
login from the UI handling logic.
Inside, the code creates an instance of XMLHttpRequest and wires its two
event handlers - onload and onerror. The former event handler will be invoked
with the Web API call is successful. The onload handler reads the responseText
property and converts the response to JSON format. The responseText could be a
single Customer, list of Customer objects, or a string message. The callback
function supplied to callWebApi() is then invoked by passing the data object to
it.
The onerror handler simply displays an error message to the end user if
anything goes wrong in the process.
Then open() method of XMLHttpRequest is called by passing the HTTP verb
string and the url. The setRequestHeader() method of XMLHttpRequest sets the
request content type to application/json.
Finally, the send() method of XMLHttpRequest is called. Depending on whether
data parameter is null or otherwise, send() takes a parameter containing the
value to be sent to the Web API. For example, during POST and PUT requests the
data parameter will be a valid Customer object that needs to be sent to the Web
API.
Get(callback: any):void {
this.callWebApi(this.baseUrl, HttpVerbs.GET,
null, callback);
}
GetByID(id: string, callback: any): void {
this.callWebApi(`${this.baseUrl}/${id}`,
HttpVerbs.GET, null, callback);
}
Post(data:ICustomer,callback: any):void {
this.callWebApi(this.baseUrl, HttpVerbs.POST,
data, callback);
}
Put(data: ICustomer, callback: any): void {
this.callWebApi(`${this.baseUrl}/${data.CustomerID}`,
HttpVerbs.PUT, data, callback);
}
Delete(id: string, callback: any): void {
this.callWebApi(`${this.baseUrl}/${id}`,
HttpVerbs.DELETE, null, callback);
}
What follows after the callWebApi() method is a series of public methods -
Get(), Post(), Put() and Delete() - that are available to the rest of the client
code. These methods internally call the callWebApi() method. Although not shown
in this example, these methods can also contain some other pre and post
processing depending on the requirements. These methods are quite
straightforward and need no explanation. Notice the use of string templates
using the back-quotes instead of string concatenation.
CustomerUI class
This completes the CustomerApiClient class. Now let's see CustomerUI class.
GetCallback(data: Array<ICustomer>): void {
alert(data.length);
}
GetByIDCallback(data:ICustomer):void {
alert(data.CustomerID);
}
PostCallback(msg:string):void {
alert(msg);
}
PutCallback(msg: string): void {
alert(msg);
}
DeleteCallback(msg: string): void {
alert(msg);
}
The CustomerUI class contains callback functions that are supplied to the
CustomerApiClient object. The GetCallback() receives an array of ICustomer
objects. Similarly, GetByIDCallback() receives a single ICustomer object. The
other three methods receive string messages.
Here, these methods simply call alert() and display some value for testing
purpose. In a more realistic here you will have all the UI handling code, say
displaying customers as a table or filling some dropdownlist or textboxes. For
the sake of simplicity we don't do much of UI handling here.
Invoking the Web API
Ok. Our CustomerApiClient and CustomerUI TypeScript classes are ready. When
you save the *.ts files Visual Studio automatically transpiles them to generate
*.js files. You may need to click the "Show All files" option in Solution
Explorer to see them.

You need to reference the AjaxHelper.js file from the Index view. So, open
the Index view and add this line:
<script src="~/Scripts/AjaxHelper.js"></script>
To test the Web API calls, set breakpoints in all the Web API actions inside
the CustomerController class. Then add a script block below the above mentioned
script reference and write the following code :
<script>
var client = new AjaxHelper.CustomerApiClient
("http://localhost:49543/api/customer");
var ui = new AjaxHelper.CustomerUI();
client.Get(ui.GetCallback);
</script>
Here, you create an object of AjaxHelper.CustomerApiClient class (remember
that AjaxHelper is the module and is analogous to namespaces in C#) by passing
the base URL of the Web API. You also create an object of AjaxHelper.CustomerUI
class.Finally, you call the Get() method of the CustomerApiClient and pass the
GetCallback method as its parameter.
If all goes well, you will reach the breakpoint in the Get() action of the
Web API and then you will see an alert box indicating the number of Customer
objects returned by the Get() action.

Here is how you can test other methods :
client.GetByID("ALFKI",ui.GetByIDCallback);
var obj = {CustomerID: "ABCDE", CompanyName:
"Company 2", ContactName: "Contact 2", Country: "USA"};
client.Post(obj,ui.PostCallback);
var obj = {CustomerID: "ABCDE", CompanyName: "Company 2",
ContactName: "Contact 2", Country: "USA"};
client.Put(obj, ui.PutCallback);
client.Delete("ABCDE",ui.DeleteCallback);
That's it for now ! Keep coding !!