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 = 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;
            }
        }
    }

创建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":1,"ClientName":"Adam","Location":"London"},
{"ReservationId":2,"ClientName":"Steve","Location":"New York"},
{"ReservationId":3,"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":3,"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

时间: 2024-10-06 16:11:00

ASP.NET MVC 4 (十二) Web API的相关文章

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

使用ASP.NET MVC和AngularJS的Web模块化管理

快速浏览标题便了解到本文要谈到公开资源平台,该平台允许快速,轻松地创建一个管理网络,并不需要在风格,导航,解决方案架构和其它跟主要任务无关的琐事上花费过多的时间. 平台视觉图和其中一块模板:(见附图一) 很长一段时间里,我们使用WPF技术模块化管理应用.我们做出的决定是将此管理迁移到网站中.最后我们得出了2个不同的产品:第一个:平台,就是这篇文章致力于介绍的,第二个是用于电子商务应用程序开发使用的集合模块. 技术运用于:(见附图二) 我们决定使用这些技术都是我们广泛应用微软产品的经验结果. 我们

Asp.Net MVC 权限控制(二):Controller级别控制

续接上篇:Asp.Net MVC 权限控制(一):使用 Authorize Roles 简单实现 由于直接在Controller上标记角色名有很大的局限性,所以本示例使用 ActionFilterAttribute 进行权限拦截. 首先创建三类标记: 1. 匿名访问标记(AnonymousAttribute)2. 登录用户访问标记(LoginAllowViewAttribute)3. 权限验证访问标记(PermissionPageAttribute) 最重要的一个权限拦截:AuthorizeFi

ASP.NET MVC Model元数据(二)

ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的生成过程,让大家能够清楚的了解到系统框架是在什么时候生成Model元数据的,对于Model元数据生成篇幅初定为两篇,本篇为它的整体的生成过程,下篇则为详细的生成过程并且会对它本身做一个粗略的介绍,希望大家看完能够有所收获 Model元数据 什么是Model元数据? 生成Model元数据的过程[一]

Myeclipse/STS 首次在本地部署配置一个Spring MVC 项目 (十二)

1. 在本地新创建一个文件夹 ,做为项目工作空间; 2. 用 Myeclipse 或 STS 进入该文件夹,该文件夹就成为项目的工作空间: 3. 就要进 窗口-首选项,配置: 环境默认编码: 1>. 常规下面 内容类型 .txt 文本 UTF-8 更新 2>. 常规 – 工作空间 , 文本文件编码 3>. 常规 – 编辑器 – 文本编辑器 – 拼写 配置 java JDK 为 项目需要的版本 比如 (1.7) : 配置 Myeclipse 下的 Servers 及 validation 

ASP.NET MVC Model验证(二)

ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决 这个问题的,并且会描述一下ModelValidator类型对象相关的类型. Model验证 Model验证简单运用示例 ModelValidator使用生成过程 自定义实现DefaultModelBinder进行验证 自定义ModelValidatorProvider 和ModelValidator  Validation

ASP.NET MVC Model绑定(二)

ASP.NET MVC Model绑定(二) 前言 上篇对于Model绑定的简单演示想必大家对Model绑定的使用方式有一点的了解,那大家有没有想过Model绑定器是在什么时候执行的?又或是执行的过程是什么样的?将在本篇为大家解除这些疑惑,在其中涉及到的一些描述类型和上下文参数会在后续的篇幅中讲到. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderProvider的简单

ASP.NET MVC 描述类型(二)

ASP.NET MVC 描述类型(二) 前言 上个篇幅中说到ControllerDescriptor类型的由来过程,对于ControllerDescriptor类型来言ActionDescriptor类型的生成则简单的多了,本章的主题有两个,第一是说明ActionDescriptor类型的生成过程,第二是描述ActionDescriptor类型的重要性,在哪里体现它的重要性呢?对于前面篇幅的学习忽略了最后控制器方法的执行过程,而在这个执行过程中ActionDescriptor类型起到了至关重要的

第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderson 翻译:谢炀(kiler) 校对:何镇汐.