Главная страница   /   25.2. Создание Web API приложения (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

25.2. Создание Web API приложения

Как мы уже объяснили, приложение Web API - это обычное приложение MVC Framework, в котором есть специальный контроллер. В качестве примера мы создали новый проект MVC Framework под названием WebServices на шаблоне Basic. В следующих разделах мы будем добавлять все регулярные компоненты приложения MVC Framework - объекты моделей, хранилище, контроллеры и представления, а затем добавим контроллер API.

Подсказка

Существует шаблон WebAPI, который создает обычный проект MVC Framework и добавляет в него пару типичных контроллеров. Как вы уже поняли, мы предпочитаем шаблоны Empty и Basic и считаем, что другие варианты просто добавляют типичный код, который лучше не использовать.

Создаем модель и хранилище

В этом примере приложения мы создали особенно простую модель под названием Reservation, которую определили в файле Reservation.cs в папке Models. Определение этой модели показано в листинге 25-1 .

Листинг 25-1: Класс модели Reservation
using System.ComponentModel.DataAnnotations;

namespace WebServices.Models
{
	public class Reservation
	{
		public int ReservationId { get; set; }
		public string ClientName { get; set; }
		public string Location { get; set; }
	}
}

Свойство ReservationId однозначно идентифицирует каждый объект модели. Свойства ClientName и Location содержат значения данных модели. В этой главе нас не интересует значение этих свойств, потому что мы собираемся работать с Web API, так что мы выбрали нечто простое и универсальное.

В последних нескольких главах мы создавали приложения, в которых данные модели создавались внутри контроллера. Мы делали это потому, что были сосредоточены на других аспектах MVC Framework, не связанных с хранением данных модели. В этой главе мы собираемся создать интерфейс хранилища и его простую реализацию. На это стоит потратить время, потому что одна из главных характеристик контроллера API - это его простота, и мы хотим ее продемонстрировать.

Мы создали новый интерфейс в файле IReservationRepository.cs в папке Models, как показано в листинге 25-2.

Листинг 25-2: Интерфейс IReservationRepository
using System.Collections.Generic;

namespace WebServices.Models
{
	public interface IReservationRepository
	{
		IEnumerable<Reservation> GetAll();
		Reservation Get(int id);
		Reservation Add(Reservation item);
		void Remove(int id);
		bool Update(Reservation item);
	}
}

Это стандартный интерфейс хранилища; он определяет методы, которые позволяют извлекать (как индивидуально, так и в коллекции), добавлять, обновлять и удалять объекты моделей.

Мы также создали класс ReservationRepository, который определили в файле ReservationRepository.cs в папке Models. Этот класс реализует интерфейс IReservationRepository и определяет несколько объектов модели. Это не тот подход, который вы бы использовали в реальном приложении, но в данной главе он подходит для наших целей. Класс хранилища показан в листинге 25-3 .

Листинг 25-3: Класс ReservationRepository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebServices.Models
{
	public class ReservationRepository : IReservationRepository
	{
		private List<Reservation> data = new List<Reservation>
		{
			new Reservation
			{
				ReservationId = 1,
				ClientName = "Adam",
				Location = "London"
			},
			new Reservation
			{
				ReservationId = 2,
				ClientName = "Steve",
				Location = "New York"
			},
			new Reservation
			{
				ReservationId = 3,
				ClientName = "Jacqui",
				Location = "Paris"
			},
		};

		private static ReservationRepository repo = new ReservationRepository();

		public static IReservationRepository getRepository()
		{
			return repo;
		}

		public IEnumerable<Reservation> GetAll()
		{
			return data;
		}

		public Reservation Get(int id)
		{
			var matches = data.Where(r => r.ReservationId == id);
			return matches.Count() > 0 ? matches.First() : null;
		}

		public Reservation Add(Reservation item)
		{
			item.ReservationId = data.Count + 1;
			data.Add(item);
			return item;
		}

		public void Remove(int id)
		{
			Reservation item = Get(id);
			if (item != null)
			{
				data.Remove(item);
			}
		}

		public bool Update(Reservation item)
		{
			Reservation storedItem = Get(item.ReservationId);
			if (storedItem != null)
			{
				storedItem.ClientName = item.ClientName;
				storedItem.Location = item.Location;
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}

Изменения в хранилище не сохраняются, так что при каждом запуске приложения в данных модель всегда будет три эталонных объекта.

Создаем контроллер Home

В проекте можно свободно смешивать обычные контроллеры и контроллеры API. На самом деле, вам придется это делать, если вы хотите обеспечить поддержку HTML-клиентов в приложении, потому что контроллеры API будут возвращать только данные объекта, а не представления. Чтобы начать использовать приложение, мы создали контроллер Home, метод действия Index которого будет визуализировать представление по умолчанию. Мы не передаем в представление объекты модели, потому что хотим реализовать веб-службу и получать все необходимые данные от контроллера API. Контроллер Home показан в листинге 25-4 .

Листинг 25-4: Контроллер Home в проекте WebServices
using System.Web.Mvc;

namespace WebServices.Controllers
{
	public class HomeController : Controller
	{
		public ActionResult Index()
		{
			return View();
		}
	}
}

Создаем представление и CSS

Мы добавили несколько стилей CSS в файл /Content/Site.css для элементов HTML, которые будут визуализированы после вызова действия Index. Эти дополнения показаны в листинге 25-5.

Листинг 25-5: Дополнения в файле Site.css
table { margin: 10px 0;}
th { text-align: left;}

.nameCol {width: 100px;}
.locationCol {width: 100px;}
.selectCol {width: 30px;}
.display { float: left; border: thin solid black; margin: 10px; padding: 10px;}
.display label {display: inline-block;width: 100px;}

Действие Index контроллера Home визуализирует представление /Views/Home/Index.cshtml, которое показано в листинге 25-6. Здесь мы не установили значения для свойства Layout, что означает, что будет использоваться макет по умолчанию. Следовательно, наши стили CSS и библиотеки jQuery (которые мы будем использовать позже) будут загружены браузером автоматически при визуализации представления. В секцию scripts мы добавили элемент script для библиотеки ненавязчивого Ajax (которую мы также будем использовать позже).

Листинг 25-6: Index.cshtml
@{
	ViewBag.Title = "Index";
}

@section scripts {
	<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
}

<div id="summaryDisplay" class="display">
	<h4>Reservations</h4>
	<table>
		<thead>
			<tr>
				<th class="selectCol"></th>
				<th class="nameCol">Name</th>
				<th class="locationCol">Location</th>
			</tr>
		</thead>
		<tbody id="tableBody">
			<tr><td colspan="3">The data is loading</td></tr>
		</tbody>
	</table>
	<div id="buttonContainer">
		<button id="refresh">Refresh</button>
		<button id="add">Add</button>
		<button id="edit">Edit</button>
		<button id="delete">Delete</button>
	</div>
</div>

<div id="addDisplay" class="display">
	<h4>Add New Reservation</h4>
	@{
		AjaxOptions addAjaxOpts = new AjaxOptions
		{
			// options will go here
		};
	}
	@using (Ajax.BeginForm(addAjaxOpts))
	{
		@Html.Hidden("ReservationId", 0)
		<p><label>Name:</label>@Html.Editor("ClientName")</p>
		<p><label>Location:</label>@Html.Editor("Location")</p>
		<button type="submit">Submit</button>
	}
</div>

<div id="editDisplay" class="display">
	<h4>Edit Reservation</h4>
	<form id="editForm">
		<input id="editReservationId" type="hidden" name="ReservationId" />
		<p><label>Name:</label><input id="editClientName" name="ClientName" /></p>
		<p><label>Location:</label><input id="editLocation" name="Location" /></p>
	</form>
	<button id="submitEdit" type="submit">Save</button>
</div>

HTML, который генерирует это представление, разбит на три секции. Каждая секция определена в элементе div с классом display, и на данный момент пользователю отображаются все три (мы изменим видимость этих элементов, когда мы будем использовать код JavaScript далее в этой главе).

Чтобы увидеть, как HTML отображается в браузере, запустите приложение. Ни одна из кнопок не будет работать, и данные не будут отображаться, но вы можете получить представление о структуре и макете, как показано на рисунке 25-1 .

Рисунок 25-1: HTML, сгенерированный представлением Index.cshtml

Когда мы закончим работу над приложением, пользователю будет показана только секция Reservations. Мы загрузим данные с сервера и заполним ими таблицу.

Секция Add New Reservation содержит форму, которая использует ненавязчивый Ajax для отправки данных к серверу и создания новых объектов Reservation в хранилище. В объекте AjaxOptions, с помощью которого мы будем настраивать запрос Ajax, пока еще нет опций, но мы вернемся и создадим их, когда остальные части приложения будут готовы.

Секция Edit Reservation позволит пользователю изменять существующий в хранилище объект Reservation. В этой секции мы не использовали форму с ненавязчивым Ajax, потому что для разнообразия хотим использовать поддержку Ajax из библиотеки jQuery напрямую (что в любом случае делает библиотека ненавязчивого Ajax).