Debugging your ASP.NET Web APIs with Fiddler

ASP.NET Web API as we all know, lets us build and expose services over HTTP without the overhead of traditional WS-* based web-services. If you are new to ASP.NET Web API, you can start here. We have also covered some Web API articles on DotNetCurry

Since Web API works over HTTP, the services are easy to interact with even without a dedicated front-end as long as we are sending/receiving required data over HTTP to the correct URL where the service is exposed. Thus we can use HTTP Proxy tools like Fiddler to intercept responses and make requests to the web service.

This is very handy in scenarios when the Services team has a head start over the front-end team who may have not started on the UI development yet. Using a tool like Fiddler, the services team can ensure the web services work as intended.

Getting Started with Fiddler

Fiddler is a free tool originally developed by Eric Lawrence from Microsoft’s IE team. Currently the product is owned by Telerik with Eric working for Telerik to continue development and support of Fiddler.

You can download it from here. On launch Fiddler looks like the screenshot below. Don’t be intimidated, we’ll walk through on how to use some of its most useful features.

fiddler

But first let’s build a ASP.NET Web API service to work on.

A Demo Web API Service

We start off with the ASP.NET MVC project and select Web API project template

new-web-api

Once we hit OK, it gives us a new Project that has two Controllers, one an MVC Controller (called HomeController) and the other an ApiController (called ValuesController).

This ValuesController is the Web API endpoint that we will be hitting using Fiddler.
Creating an in-memory Harness
For the sake of simplicity, we’ll use one Entity called Blog and store all its instances in a generic list. To maintain this List across sessions, we’ll stuff it in the Application Context.

public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Post { get; set; }
public bool IsDeleted { get; set; }
}


Listing 1. Blog.cs

Our final listing for the ValuesController is as follows:

public class ValuesController : ApiController
{
List<Blog> BlogContext;

public ValuesController()
{
  if (HttpContext.Current.Application["blogContext"] == null)
  {
   HttpContext.Current.Application["blogContext"] = new List<Blog>();
  }
   BlogContext = (List<Blog>)(HttpContext.Current.Application["blogContext"]);
  }

  // GET api/values
  public IEnumerable<Blog> Get()
  {
   return BlogContext;
  }

  // GET api/values/5
  public Blog Get(int id)
  {
   Blog current = BlogContext.Find(b => b.Id == id && !b.IsDeleted);
   if (current == null)
   {
    throw new HttpResponseException(HttpStatusCode.NotFound);
   }
   else
   {
    return current;
   }
  }

  // POST api/values
  public void Post([FromBody]Blog value)
  {
   value.Id = BlogContext.Count + 1;
   BlogContext.Add(value);
  }

  // PUT api/values/5
  public void Put(int id, [FromBody]Blog value)
  {
   Blog current = BlogContext.Find(b => b.Id == id);
   if (current == null || current.IsDeleted)
   {
    throw new HttpResponseException(HttpStatusCode.NotFound);
   }
   else
   {
    current.Title = value.Title;
    current.Post = value.Post;
    current.IsDeleted = value.IsDeleted;
   }
  }

  // DELETE api/values/5
  public void Delete(int id)
  {
   Blog current = BlogContext.Find(b => b.Id == id);
   if (current == null || current.IsDeleted)
   {
    throw new HttpResponseException(HttpStatusCode.NotFound);
   }
   else
   {
    current.IsDeleted = true;
   }
  }
}

Listing 2: ValuesController.cs

With our in-memory harness ready, we are ready to test out if our Blogging Service is serving up Blogs, Adding new Posts, Updating Existing Ones and Deleting posts if required. Since we don’t yet have a UI for the service, we will debug and test it using Fiddler.

Debugging our Web API Service with Fiddler

Once we start Fiddler, it immediately starts monitoring all HTTP traffic. This can be overwhelming and cause a lot of noise in which our test traffic may get lost. As a result, the first thing we do is enable a ‘Filter’ in Fiddler

Enabling Filters in Fiddler

Filters, as is implied, narrow down the scope of Fiddler’s monitoring and reporting; thus helping reduce noise in the Web Sessions pane. To enable Filter, on the Right Hand Side Pane, select the Filter Tab and enable Filters. Next ensure Hosts are setup to ‘Show Intranet Hosts’ only. If you have multiple sites running at the same time, you can reduce things further by specifying a Host Filter, or Client Filter or Request Headers and so on. In our case, only enabling Intranet Hosts suffice

fiddler-filters

Monitoring ‘Get’ Requests

Since our BlogContext is empty, our first Get Request will return an Empty JSON. We can verify this as follows

1. Start the Application in IE

2. Navigate to the http://localhost:62047/api/Values/

3. Now in Fiddler, on the Right Hand Pane, select the appropriate Web Session

fiddler-get
4. Once selected, on the Right Hand Pane, select the Inspectors Tab and select JSON as shown below. As you can see, no data was returned the first Time around, which is correct
fiddler-empty-json

POSTing data to Web Service using the Fiddler Composer

Since there are no posts in the BlogContext, we didn’t get any result back, so let’s post some data to the Web Service and see if new data is added.

To Post Data, we have to do the following

1. Select the Fiddler Composer

2. Update the URL to http://localhost:62047/api/Values/

3. Update the Action to POST

4. Update the Request BODY with the JSON equivalent for the Blog entity

5. Put a break point on the Api Service’s Post Method (in Visual Studio)

6. Hit Execute in Fiddler.

fiddler-post

7. As the Service hits the breakpoint we can see that the JSON Data passed above has been passed onto the server side correctly (and the Id’s been updated on the Server).

server-side-post

8. Now if we do a GET request again (we can simply use the composer and change Request Type to GET instead of POST, or use the Browser) we will see the JSON Result returned as follows

fiddler-get-data

We can also Update the Post using the Composer as follows (note the PUT action)

fiddler-put

We can similarly try out the other HTTP actions like Delete using the Composer as follows (Note the Delete action and the Query String parameter for Id)

fiddler-delete

That covers all the actions we had implemented.

Conclusion

ASP.NET Web API services work over HTTP and we can test these services using Proxy Applications like Fiddler by sending data in the correct format to the services via appropriate HTTP requests (like GET, POST, PUT, DELETE etc.)

Fiddler is a powerful application for intercepting and debugging requests and responses over HTTP and we just saw a quick overview of its capabilities.

The entire source code can be downloaded here (Github)

7 comments:

  1. I am curious why I see two calls to my api controller in fiddler?

    ReplyDelete
  2. I am curious why I see two calls to my api controller in fiddler?

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. I was following the example, im having trouble with POST method and
    it gives me 415 - Unsupported Media Type, heres the code im using

    Controller
    public HttpResponseMessage Post(Customer customer){
    if (ModelState.IsValid){
    db.Customers.Add(customer);
    db.SaveChanges();
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, customer);
    MediaTypeHeaderValue contentType = response.Content.Headers.ContentType;
    response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = customer.Id }));
    response.Content.Headers.ContentType = contentType;
    return response;
    }
    else
    {
    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    }
    }

    What could it be the mistake? Any help would be appreciated

    ReplyDelete
  5. alexander ocampo hidalgo,

    You need setup the content-type as below:

    User-Agent: Fiddler
    Host: YourURL
    Content-Type: application/json

    ReplyDelete