系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html
经过前2节的介绍,我们已经把数据访问层搭建好了,从本章开始就是Web Api部分了。在正式开始之前,再一次回顾一下Web Api的应用场景:Web Api可以与 MVC,WebForm结合使用,也可以作为一个单独的Web服务。在正式讨论Web Api的配置以及如何构造我们的URI来消费资源之前,我们必须理解Http方法与我们将要访问的资源之间的关系。举个简单的例子,我们把模型”Course”作为我们访问的资源,下面就列举了访问这个资源的http方法:
Action | HTTP Verb | Relative URI |
获取所有课程信息 | GET | /api/courses |
根据某个Id获取单个课程 | GET | /api/courses/id |
新增一个课程 | POST | /api/coursesNew course is sent in POST body |
更新一个课程 | PUT or PATCH | /api/courses/idUpdated course is sent in POST body |
删除一个课程 | DELETE | /api/courses/id |
右击解决方案->添加新建项目
下一步:
点击确定
在创建好项目之后,我们可以在App_Start文件夹下看到“WebApiConfig”类。这个类就是用来配置路由信息的,这个类最终会在“Global.asax”的Application_Start()方法中被调用,后面我们会在这个这个类里面配置多条路由信息。
配置第一个路由:
config.Routes.MapHttpRoute( name: "Courses", routeTemplate: "api/courses/{id}", defaults: new {controller="courses", id = RouteParameter.Optional } );
分析一下上面这段代码:我们创建了一个Courses的路由规则,这个路由模板会匹配到“api/courses/{id}”的URI,在这个模板定义了2个默认值(api,courses)以及一个可选值(id)。对于“/api/courses or /api/courses/5”URI就会被我们的路由模板匹配到,同时“/api/courses”URI也会被匹配到,因为Id是可选的。
Web Api中的Controller是用来处理客户端Http请求的(与MVC中的Controller类似),首先,创建Controller——右击Controller文件夹->新建项->控制器
然后出现下面窗口:
选择Web API 2控制器-空,并命名为CoursesController。然后确定
打开刚才创建的Controller,可以看到我们创建的类继承自“ApiController”。同时对于这个类的类名必须是“CoursesController”,因为在Web Api中默认的控制器选择方式是寻找所有继承自“ApiController”类并且这个类是以“Courses”开头(这是在我们的路由规则中配置的)的控制器。
首先,我们创建上述表格列举到的前2个方法(GetAllCourses,GetCourseById)
方法的选择是智能的,如果我们创建了2个方法Get()和GetCourse(int id),假设我们发送一个GET请求并且URI是“/api/courses/5”,那么“GetCourse(int id)”方法就会被选择执行,这是因为方法是以Get开头而且URI中包含Id的值。这种选择方式同样适用以其他的Http方法(put,delete,post),下面上代码:
public class CoursesController : ApiController { public List<Course> Get() { ILearningRepository repository = new LearningRepository(new LearningContext()); return repository.GetAllCourses().ToList(); } public Course GetCourse(int id) { ILearningRepository repository = new LearningRepository(new LearningContext()); return repository.GetCourse(id); } }
当我们创建一个Get请求并且URI是“http://localhost:{your_port}/api/courses”时候,Get()方法会被选择调用,下面是相应的部分代码:
[ { "Id": 1, "Name": "History Teaching Methods 1", "Duration": 3, "Description": "The course will talk in depth about: History Teaching Methods 1", "CourseTutor": { "Courses": [], "Id": 1, "Email": "[email protected]", "UserName": "AhmadJoudeh", "Password": "SWDQNPSE", "FirstName": "Ahmad", "LastName": "Joudeh", "Gender": 0 }, "CourseSubject": { "Courses": [], "Id": 1, "Name": "History" }, "Enrollments": [] }, { "Id": 2, "Name": "History Teaching Methods 2", "Duration": 3, "Description": "The course will talk in depth about: History Teaching Methods 2", "CourseTutor": { "Courses": [], "Id": 1, "Email": "[email protected]", "UserName": "AhmadJoudeh", "Password": "SWDQNPSE", "FirstName": "Ahmad", "LastName": "Joudeh", "Gender": 0 }, "CourseSubject": { "Courses": [], "Id": 1, "Name": "History" }, "Enrollments": [] },
如果你发送一个Get请求并且URI是“http://localhost:{your_port}/api/courses/5”。那么GetCourse(int id)将会被选择调用执行。但是很遗憾在调用这个方法之后就会产生一个异常,这个异常信息简单来说就是“序列化对象的时候出现了循环依赖”,换句话说就是对象间循环引用(Course>Enrollment>Course>Enrollment>etc…)
到目前为止我们已经让Web Api跑起来了,但仍然有很多不足之处:
返回对象时出现循环依赖,可以通过模型工厂模式解决。
我们返回了领域模型中所有的字段给客户端,然而有一些敏感信息不应该返回(例如:password字段),解决方案:模型工厂模式
每一个返回给客户端的资源都应该包含一个URI以便客户端查询,解决方案依旧是模型工厂模式。
对于返回单个资源,我们应当返回相应的状态码(例如:成功200,资源未找到404等),解决方案:HttpResponseMessage对象
在每个方法里我们都实例化了一个repository,这个对象包含了一些昂贵的操作(例如:数据库连接),解决方案:依赖注入模式
对于返回的Json对象格式是以“帕斯卡”风格的(例如“FirstName”),然而我们的Api有很大的可能被带有Javascript的客户端消费,对于JS开发者来说可能更适合“驼峰”风格(例如”firstName”)的数据。解决方案:配置Json格式。
ok,下一章我们就着重解决上述的问题
本章代码:http://yun.baidu.com/share/link?shareid=2010367762&uk=17559114&third=0