ASP.NET MVC 4 (十二) Web API
Web API属于ASP.NET核心平台的一部分,它利用MVC框架的底层功能方便我们快速的开发部署WEB服务。我们可以在常规MVC应用通过添加API控制器来创建web api服务,普通MVC应用程序控制器根据用户请求的action方法返回ActionResult,而web api服务返回的则是json封装的模型数据。
在开始下面的内容前先给出相关类与接口的代码:
public interface IReservationRepository { IEnumerable<Reservation> GetAll();
Reservation Get(int id);
Reservation Add(Reservation item);
void Remove(int id);
bool Update(Reservation item);
} public class Reservation { public int ReservationId { get; set; }
public string ClientName { get; set; }
public string Location { get; set; }
} public class ReservationRepository : IReservationRepository {
private List<Reservation> data = new List<Reservation> {
new Reservation {ReservationId = , ClientName = "Adam", Location = "London"},
new Reservation {ReservationId = , ClientName = "Steve", Location = "New York"},
new Reservation {ReservationId = , 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() > ? matches.First() : null;
} public Reservation Add(Reservation item) {
item.ReservationId = data.Count + ;
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;
}
}
}
创建API控制器
在已有的MVC WEB应用中添加API控制器来创建WEB服务,VS的添加控制器对话框中可以选择创建API控制器,我们可以选择“Empty API controller”创建不包含任何方法的空API控制器,手工添加对应各个WEB服务操作的方法,一个完整的API控制类类似:
using System.Collections.Generic;
using System.Web.Http;
using WebServices.Models; namespace WebServices.Controllers {
public class ReservationController : ApiController {
IReservationRepository repo = ReservationRepository.getRepository(); public IEnumerable<Reservation> GetAllReservations() {
return repo.GetAll();
} public Reservation GetReservation(int id) {
return repo.Get(id);
} public Reservation PostReservation(Reservation item) {
return repo.Add(item);
} public bool PutReservation(Reservation item) {
return repo.Update(item);
} public void DeleteReservation(int id) {
repo.Remove(id);
}
}
}
当我们从浏览器访问 /api/reservation时得到的GetAllReservations方法封装的JSON数据,在IE10中得到的结果类似:
[{"ReservationId":,"ClientName":"Adam","Location":"London"},
{"ReservationId":,"ClientName":"Steve","Location":"New York"},
{"ReservationId":,"ClientName":"Jacqui","Location":"Paris"}]
如果是Chrome或者Firefox结果则是XML:
<ArrayOfReservation>
<Reservation>
<ClientName>Adam</ClientName>
<Location>London</Location>
<ReservationId>1</ReservationId>
</Reservation>
<Reservation>
<ClientName>Steve</ClientName>
<Location>New York</Location>
<ReservationId>2</ReservationId>
</Reservation>
<Reservation>
<ClientName>Jacqui</ClientName>
<Location>Paris</Location>
<ReservationId>3</ReservationId>
</Reservation>
</ArrayOfReservation>
这种区别源于浏览器提交的Accept头,IE10发送的Accept头类似:
...
Accept: text/html, application/xhtml+xml, */*
...
表示IE10优先接受 text/html,接下来是application/xhtml+xml,如果前两者不可行, */*表示接受任何格式。Web API支持XML和JSON两种格式,但是优先使用JSON,所以IE10得到的*/*选择的JSON格式。Chrome发送的Accept头类似:
...
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
...
Chrome优先接受application/xml,所以WEB API使用XML格式发送数据。
理解API控制器如何作用
在IE10中如果访问/api/reservation/3,得到的JSON数据类似:
{"ReservationId":,"ClientName":"Jacqui","Location":"Paris"}
这里得到的ReservationIdvalue=3的对象数据,这和MVC的路径映射很相似,实际上确实也是这样,API有自己的的路径映射,定义在 WebApiConfig.cs文件中:
using System.Web.Http; namespace WebServices {
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
这里的路径映射非常类似于MVC控制器的路径映射,但是所用的路径映射表和配置类都来自于System.Web.Http命名空间,Microsoft在这个命名空间复制了MVC的对应的类,这样做使得我们可以脱离MVC单独使用WEB API。这里注册的API路径映射最后在global.asax中通过WebApiConfig.Register(GlobalConfiguration.Configuration)注册到全局配置文件中。
和MVC控制器通过URL选择action方法不同,API控制器根据HTTP请求方法的不同来选择API控制器方法。API控制器方法的命名规则一般是HTTP方法作为前缀加上控制器的名称,比如GetReservation(这只是常规做法,DoGetReservation、ThisIsTheGetAction都是允许的),我们从浏览器访问/api/reservation所用的HTTP方法为GET,API控制器会查找所有包含GET的所有控制器方法,GetReservation和GetAllReservations都在考虑之类,但是具体选择哪个还参考了所带的参数,访问/api/reservation没有任何参数,因此API控制器选择了GetAllReservations,访问/api/reservation/3自然就选择了GetReservation。由此我们也知道PostReservation、PutReservation、DeleteReservation分别对应HTTP的Post、Put、Delete三种方法(WEB API的Representation State Transfer - REST)。
PutReservation方法命名多少有点不自然,我们更习惯称呼它为UpdateReservation,和MVC一样,System.Web.Http也提供一些特性可以应用于控制器方法:
public class ReservationController : ApiController {
IReservationRepository repo = ReservationRepository.getRepository(); public IEnumerable<Reservation> GetAllReservations() {
return repo.GetAll();
} public Reservation GetReservation(int id) {
return repo.Get(id);
} [HttpPost]
public Reservation CreateReservation(Reservation item) {
return repo.Add(item);
} [HttpPut]
public bool UpdateReservation(Reservation item) {
return repo.Update(item);
} public void DeleteReservation(int id) {
repo.Remove(id);
}
}
这里通过HttpPost特性指定CreateReservation对应HTTP的POST请求,HttpPut指定UpdateReservation对应HTTP的PUT请求,MVC也有类似的特性,但是注意它们虽然同名但是定义在System.Web.Http命名空间。
使用WEB API
如同常规WEB服务,我们可以有多种方式来调用WEB API,比如windows form程序、其他ASP.NET应用程序,这里给出如何在当前MVC应用中利用javascript脚本来使用web api。
视图文件index.cshtml:
@{ ViewBag.Title = "Index";}
@section scripts {
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="~/Scripts/Home/Index.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 {
OnSuccess = "getData",
Url = "/api/reservation"
};
}
@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>
Index.js:
function selectView(view) {
$('.display').not('#' + view + "Display").hide();
$('#' + view + "Display").show();
} function getData() {
$.ajax({
type: "GET",
url: "/api/reservation",
success: function (data) {
$('#tableBody').empty();
for (var i = 0; i < data.length; i++) {
$('#tableBody').append('<tr><td><input id="id" name="id" type="radio"'
+ 'value="' + data[i].ReservationId + '" /></td>'
+ '<td>' + data[i].ClientName + '</td>'
+ '<td>' + data[i].Location + '</td></tr>');
}
$('input:radio')[0].checked = "checked";
selectView("summary");
}
});
} $(document).ready(function () {
selectView("summary");
getData();
$("button").click(function (e) {
var selectedRadio = $('input:radio:checked')
switch (e.target.id) {
case "refresh":
getData();
break;
case "delete":
$.ajax({
type: "DELETE",
url: "/api/reservation/" + selectedRadio.attr('value'),
success: function (data) {
selectedRadio.closest('tr').remove();
}
});
break;
case "add":
selectView("add");
break;
case "edit":
$.ajax({
type: "GET",
url: "/api/reservation/" + selectedRadio.attr('value'),
success: function (data) {
$('#editReservationId').val(data.ReservationId);
$('#editClientName').val(data.ClientName);
$('#editLocation').val(data.Location);
selectView("edit");
}
});
break;
case "submitEdit":
$.ajax({
type: "PUT",
url: "/api/reservation/" + selectedRadio.attr('value'),
data: $('#editForm').serialize(),
success: function (result) {
if (result) {
var cells = selectedRadio.closest('tr').children();
cells[1].innerText = $('#editClientName').val();
cells[2].innerText = $('#editLocation').val();
selectView("summary");
}
}
});
break;
}
});
});
第一次访问index视图HTML界面装载完成后调用JS函数selectView("summary"),它显示ID=summaryDisplay的DIV块,隐藏其他的addDisplay、editDisplay块,然后通过调用JS函数getData(),getData使用GET方法向WEB API请求数据,返回的数据每个项目一行在表格中。summaryDisplay底部有Refresh、Add、Edit、Delete四个按钮,这些按钮的点击在“$("button").click(function (e)”处理;点击Refresh时调用getdata刷新数据;点击add时隐藏其他DIV块,显示addDisplay DIV块,这个DIV块创建一个AJAX表单,POST方法提交到API控制器的CreateReservation;EDIT按钮根据当前的选项从/api/reservation/{id} GET相应的对象后显示editDisplay DIV块,同时隐藏其他DIV块;点击editDisplay DIV块中的submitEdit按钮,JS使用PUT方法请求/api/reservation/{id}调用API控制器的UpdateReservation方法修改数据,完成后再次显示summaryDisplay DIV块,隐藏其他DIV块;点击delete按钮则是使用DELETE方法请求/api/reservation/{id}调用控制器方法DeleteReservation删除对象,完成后删除summaryDisplay DIV块中的相应行。
以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369。
ASP.NET MVC 4 (十二) Web API的更多相关文章
- ASP.NET MVC 提供与访问 Web Api
ASP.NET MVC 提供与访问 Web Api 一.提供一个 Web Api 新建一个项目,类型就选 "Web Api".我用的是MVC5,结果生成的项目一大堆东西,还编译不过 ...
- asp.net MVC中实现调取web api
public ActionResult Index(string city) { if (string.IsNullOrEmpty(city)) { city = "上海"; } ...
- [转]ASP.NET MVC学习系列(二)-WebAPI请求 传参
[转]ASP.NET MVC学习系列(二)-WebAPI请求 传参 本文转自:http://www.cnblogs.com/babycool/p/3922738.html ASP.NET MVC学习系 ...
- ASP.NET MVC Model元数据(二)
ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...
- ASP.NET MVC 控制器激活(二)
ASP.NET MVC 控制器激活(二) 前言 在之前的篇幅中,用文字和图像来表示了控制器的激活过程,描述的角度都是从框架默认实现的角度去进行描述的,这样也使得大家都可以清楚的知道激活的过程以及其中涉 ...
- 表现层及ASP.NET MVC介绍(二)
表现层及ASP.NET MVC介绍(二) 最近的更新速度越来越慢,主要是项目上比较忙,封装EasyUi也要花很多时间.不过大家请放心,本系列不会半途夭折,并且代码干货也会持续更新.本文继续介绍表现层和 ...
- Mvc 6 中创建 Web Api
如何在Mvc 6 中创建 Web Api以及如何脱离IIS实现自我托管 微软推出的Asp.net vNext(asp.net 5.0)的其中的一个目标就是统一mvc 和web api 的框架.接下来我 ...
- ASP.NET MVC 描述类型(二)
ASP.NET MVC 描述类型(二) 前言 上个篇幅中说到ControllerDescriptor类型的由来过程,对于ControllerDescriptor类型来言ActionDescriptor ...
- ASP.NET MVC Model验证(二)
ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决这个问题的,并且会描述一下 ...
随机推荐
- Linux进程优先级系统——设置实时进程优先级
前言 最近研发的产品出了点小bug,最后查到根本原因是,其中一个进程A使用基于FIFO的实时进程优先级,而另一个进程B是使用普通调度的进程优先级,而A和B两个进程是互相通信的,进程B会被饿死,而进程A ...
- Standard Series Values in a Decade for Resistances and Capacitances E24 E48 E96
E3 50% tolerance (no longer used)E6 20% tolerance (now seldom used)E12 10% toleranceE24 ...
- Golang 实现 set 集合,变相实现 切片去重、排序 功能
Java 中的集合(set)去重很方便,PHP 中的数组值去重,就更加方便,一个函数搞定:array_unique(),Golang 中就比较苦逼了,官方没有提供对“切片去重”的功能,而项目中,又经常 ...
- uva 1629切蛋糕(dp)
有一个n行m列的网格蛋糕,上面有一些樱桃.求使得每块蛋糕上都有一个樱桃的分割最小长度 思路:dp. #include<cstdio> #include<cstring> #in ...
- Knockout.Js官网学习(Mapping高级用法二)
使用ignore忽略不需要map的属性 如果在map的时候,你想忽略一些属性,你可以使用ignore累声明需要忽略的属性名称集合: " }; var mapping = { 'ignore' ...
- Linux之路,起步虽晚,迈步才会成功(2013.08.09)
工作太忙,很久没写文章了.以前基本没有接触过,但是基于现在工作的状态,对于linux这种博大精深的东西,速成是没有可能的,只能积累,起步虽晚,迈步才会成功,以此勉励自己.
- Java+大数据开发——Hadoop集群环境搭建(一)
1集群简介 HADOOP集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起 HDFS集群: 负责海量数据的存储,集群中的角色主要有 NameNode / DataN ...
- pandas基础用法——索引
# -*- coding: utf-8 -*- # Time : 2016/11/28 15:14 # Author : XiaoDeng # version : python3.5 # Softwa ...
- Windows批处理 调用程序后 不等待子进程 父进程继续执行命令
从DOS过来的老鸟应该都知道批处理,这个功能在WINDOWS中仍然保留着.批处理 说白了就是把一系列DOS命令写在一个文本文件里,然后把这个文件命名为XXX.bat(WINXP以后的系统也可以命名为* ...
- android保持服务不休眠(持续运行)以及唤醒屏幕的方法
假设有这样一个应用场景,一个服务一直在默默的工作(比如即时地获取服务器的消息),即使在屏幕已经因为长时间无操作而关闭,或者用户按了电源键让屏幕关闭,手机进入休眠状态,他必须依然在工作中.一旦从服务器获 ...