Refactoring to Web API

In this tutorial we will walk through how to refactor the application to retrieve data asynchronously from ASP.NET Web API.

Prequisites

Video Tutorial

Watch the video below to follow along with the tutorial and to get an introduction to Web API. The tutorial below contains the code used in the video to refactor the application to Web API. This tutorial is meant to be used along side the video.

Video: Web API Introduction and Demo

Tutorial

We are going to start by refactoring the ~/Controllers/PeopleController.cs by moving the logic of PeopleController.All() into a Web API controller.

Create the People Service API controller
  • Create a new API Controller by right clicking on the Controllers direction and clicking Add > Controller...
  • Rename the controller PeopleServiceController and select Empty API controller from the Template drop down list.
  • Add a method for retrieving an list of People. Add the following code to the controller.

private readonly PersonRepository _personRepository = new PersonRepository();
private readonly AccidentRepository _accidentRepository = new AccidentRepository();

public IEnumerable<PersonViewModel> Get()
{
	var viewData = new List<PersonViewModel>();

	var people = _personRepository.GetAllPeople();
	foreach (var p in people)
	{
		var person = new PersonViewModel
		{
			PersonId = p.Id,
			PersonName = p.Name,
			ThrowCount = _accidentRepository.GetThrowCountByPerson(p),
			HitCount = _accidentRepository.GetHitCountByPerson(p)
		};
		viewData.Add(person);
	}

	return viewData;
}


Optional: Add a Get by Id method to the PeopleServiceController class

The video adds this method to demonstrate how you can retrieve a single Person. This functionality is not currently used by the application, but it is good to give it a try.
  • Open the ~/Controllers/PeopleServiceController.cs class and add the following method:

public PersonViewModel Get(int id)
{
	var person = _personRepository.GetPersonById(id);
	if (person == null) throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

	return new PersonViewModel
	{
		PersonId = person.Id,
		PersonName = person.Name,
		ThrowCount = _accidentRepository.GetThrowCountByPerson(person),
		HitCount = _accidentRepository.GetHitCountByPerson(person)
	};
}


Clean Up PeopleController
  • Open the ~/Controllers/PeopleController.cs class and replace all of the All() method with:

public ActionResult All()
{
        return View();
}


Clean Up the View
  • Open the /Views/People/All.cshtml file.
  • Remove the strongly typed view
@model ThumpThumpBus.Models.ViewModels.AllPeopleViewModel
  • Remove the logic for displaying the View Model data.
@foreach (var p in Model.People)
{
	<tr>
		<td><h5>@p.PersonName</h5></td>
		<td><h5>@p.ThrowCount</h5></td>
		<td><h5>@p.HitCount</h5></td>
	</tr>
}


Create the Accident Service API controller
  • Create a new API Controller by right clicking on the Controllers direction and clicking Add > Controller...
  • Rename the controller AccidentServiceController and select Empty API controller from the Template drop down list.
  • Add a method for retrieving an list of all Accidents. Add the following code to the controller.
private readonly PersonRepository _personRepository = new PersonRepository();
private readonly AccidentRepository _accidentRepository = new AccidentRepository();

public IEnumerable<AccidentViewModel> Get()
{
	var viewData = new List<AccidentViewModel>();
	var accidents = _accidentRepository.GetAllAccidents();
	foreach (var a in accidents)
	{
		var avm = new AccidentViewModel();
		avm.AccidentId = a.Id;
		avm.AccidentReason = a.Reason;
		avm.ThrowerName = _personRepository.GetPersonById(a.ThrowerId).Name;
		avm.VictimName = _personRepository.GetPersonById(a.VictimId).Name;
		viewData.Add(avm);
	}

	return viewData;
}
  • Update the ~/Views/Accidents/Index.cshtml view. By adding the following script. To call the Web API method asynchronously.
<script type="text/javascript">
$(document).ready(function () {
	// Send an AJAX request
	$.getJSON("api/AccidentService/",
			function (data) {
				// On success, 'data' contains a table of People.
				$.each(data, function (key, val) {
					var str = "<li><mark>" + val.ThrowerName + "</mark> threw <mark>" + val.VictimName + "</mark> under the bus for: <mark>" + val.AccidentReason + "</mark></li>";
					$("ol.round").append(str);
				});
			});
});
</script>

  • While in the ~/Views/Accidents.Index.cshtml view remove the following code so the view isn't strongly typed.
@model ThumpThumpBus.Models.ViewModels.AccidentLogViewModel
  • Delete the following code used to display the view models data.
@foreach(var a in Model.Accidents)
{
	<li><mark>@a.ThrowerName</mark> threw <mark>@a.VictimName</mark> under the bus for: <mark>@a.AccidentReason</mark></li>
}


Clean Up AccidentsController's Index() method
  • Replace the current Index() method with the following code.
public ActionResult Index()
{
    return View();
}


Refactor AccidentsController to move accident report to Web API
  • Update the AccidentServiceController class by adding the code to the class.
public HttpResponseMessage Post(Accident accident)
{
	_accidentRepository.AddAccident(accident);

	var uri = Url.Link("DefaultApi", new {id = accident.Id});
	var response = Request.CreateResponse(HttpStatusCode.Created, accident);
	response.Headers.Location = new Uri(uri);
	return response;
}
  • Update the ~/Views/Accidents/Report.cshtml view to call the Post method when the user clicks the submit button.
<script type="text/javascript">
	$(document).ready(function () {
		$("#SubmitButton").click(function (event) {
			event.preventDefault();
			var vId = $("#SelectedVictimId").val();
			var tId = $("#SelectedThrowerId").val();
			var r = $("#Reason").val();
			var data = { throwerId: tId, victimId: vId, reason: r };

			jQuery.ajaxSettings.traditional = true;
			$.ajax({
				url: "/api/AccidentService",
				type: "POST",
				data: JSON.stringify(data),
				contentType: 'application/json; charset=utf-8',
				success: function () {
					$("<p><mark>Thank for your selling out your colleague.  We will send a bus over shortly.</mark></p>").insertBefore("form");
					$("#SelectedVictimId").val(1);
					$("#SelectedThrowerId").val(1);
					$("#Reason").val("");
				}
			});
		});
	});
</script>
  • Remove the following logic from the view.
@if(Model.IsSubmitted)
{
	<p><mark>Thank for your selling out your colleague.  We will send a bus over shortly.</mark></p>
}


Clean up the AccidentController's Report method
  • Delete the following method.
[HttpPost]
public ActionResult Report(ReportAccidentViewModel model)
{
    var accident = new Accident { Reason = model.Reason, ThrowerId = model.SelectedThrowerId, VictimId = model.SelectedVictimId };
    _accidentRepository.AddAccident(accident);

    var viewData = new List<PersonViewModel>();
    var people = _personRepository.GetAllPeople();
    foreach (var p in people)
    {
        var person = new PersonViewModel();
        person.PersonId = p.Id;
        person.PersonName = p.Name;
        person.ThrowCount = _accidentRepository.GetThrowCountByPerson(p);
        person.HitCount = _accidentRepository.GetHitCountByPerson(p);
        viewData.Add(person);
    }

    model.People = viewData;
    model = new ReportAccidentViewModel(viewData);
    return View(model);
}
  • Remove the Attribute from the remaining Report() method by deleting the following line.
[HttpGet]

Conclusion

You have just updated the Thump Thump Bus to call various Web API methods asynchronously from the client browser.

Last edited Jun 11, 2012 at 11:49 AM by sgmeyer, version 10

Comments

No comments yet.