( 这篇文章主要来源为ASP.NET官网的教学,在经过小弟的改编与添加一堆杂七杂八的东西XD )
前期提要
通常漫画前面都会有一个前期提要,毕竟前篇拖的时间也有点久了,所以这边就稍微的剧情回顾一下吧XD,首先,我们谈到ASP.NET MVC Web API,其实Web API就是透过HTTP的一个Web Service,所谓的Service,就是一个服务窗口,你可以透过这个窗口进行某些事情 ( 例如:传简讯的Web Service,就可以把电话号码与内容透过HTTP呼叫此服务,然后就开始发送。 ),而前端的设备,举凡普通的网页,到最夯的Win 8 Metro Style ( 不是淡定红茶喔! ),都可以利用使用Web Service,因为是用最常用的HTTP阿!!,而Web Service通常会回传个讯息回来 ( 例如:简讯服务可能会回传有没有发送成功 ),而ASP.NET MVC Web API预设回传的资料是使用JSON格式,而ASP.NET MVC Web API又是使用Rest Style风格,也就是利用HTTP标准的Get、Put、Delete、Post四种命令,来对应CRUD…但到底要怎么做呢!?让我们拭目以待!
( 好长的前期提要喔= =…突然发现写漫画前期提要的人,真是厉害… )
新增一个空专案开始
这次我们的目标是建立一个简单的客户新增修改删除查询系统,整个过程并不会动到资料库,我们会用Collection模拟的方式来进行,所以真的不会用到资料库。
建立要撰写JavaScript的View
首先,我们当然是要先新增一个ASP.NET MVC 4 Web Application专案,然后取个帅气的专案名子( 相信我,有帅气的名子,专案就成功一半了,但记得要取和这个专案有关的名子喔!这样未来才不会误删- - )
接下来,我们选择空专案吧,自己来比较有感觉嘛XDD,接下来,View Engine就选择Razor吧,自从ASP.NET MVC 3开始,Razor就变成小弟的最爱了。
接下来,我们先建一个Controller。
我们取名为HomeController,然后Template选择Empty Controller,这个Controller未来只会建立一个View,这个View里面,小弟我会去撰写JavaScript的程式码 ( 会用jQuery这个函式库来简化处理原本拢长的JavaScript。 )
建好的程式码如下,也不用做甚么变动。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcWebApiCRUDDemo.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
}
接下来,我们要建立这个Controller的View,建立这个View很简单,我们只要在程式码的Public ActionResult Index()的Index这几个字上,按下滑鼠右键,就会出现如下图的视窗,然后就可以轻松地加上View ( 超适合小弟的懒人方法!! )
接下来,我们看一下View的name正不正确,然后取消勾选Use a layout or master page,那是因为目前我们也没有用到master或是layout的机制,所以直接取消就可以了。
到这边,这个View暂时先这样就可以了,我们可以run run看;没错,就会如下图,空白一片,我很想加上Hello World,但现在毕竟不是做ASP.NET MVC 4的Demo,所以暂时先这样就可以了,晚一点,我们会回头再加上东西。
开始建立资料
好,看了那么多图,应该比较不会想睡觉了吧XDD,接下来我们Key一下程式码吧。
建立客户类别
我们要先建立好我们的Model,而这次整个专案,最重要的就是客户这个Model,所以我们要先建立这个Class,我们从Model的资料夹准备加入一个新的Class。
接下来,我们选择类别,并命名为Customer。
然后加入Id、Name、Phone,就是这么的简单,如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcWebApiCRUDDemo.Models
{
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
}
}
到这边,我们Model就建立好了,这个Customer就像是一笔资料一样,接下来,我们要开始准备实做仓储的地方,也就是像存放这些Customer的Collection。
实作Repository Patten
这种做法实际上是一种Repository Patten,又称为仓储模式,它的用途是在资料库间多加一层,让我们将资料存取的方法给隔离,所以我们就不会在整个专案世界到处都塞满一堆SQL,我们会把所有存取资料库的方法都放到Repository Class里面来,所以就如其名,他就像是一个仓库,存放著所有的资料,我们需要甚么资料,就透过他来提取 ( 当然,新增、删除也是噜 ),这里小弟我这边就不细讲了,基本上这个东西和ASP.NET MVC是完全没关系的,但我们通常写ASP.NET MVC的时候,都会利用这种Patten,来与资料库沟通,有兴趣的可以去Google一下=v=。
首先,我们一样在Model的目录下加上一个介面,不要看到介面就觉得很可怕,想离开这页XDD,就如小弟说,这个Patten,是和ASP.NET MVC无关的,就算真的不懂,也可以照样画葫芦,很简单的,而且如果人家问的话,就可以很臭屁的说,这是一个Patten!!,这样有没有感觉很赞了XDDD。
接下来,我们要在这个介面里面定义一些方法,看到这些方法,有没有豁然开朗的感觉了!?,没错,我们这边定义的方法,其实就是CRUD嘛,就如上面所说,我们就是打算透过Repository Class的这些方法来操作资料库的CRUD,这样子,我们的SQL就不换散落在世界各地了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcWebApiCRUDDemo.Models
{
//这里要实作ICustomerRepository
public class CustomerRepository :ICustomerRepository
{
//我们利用List来充当资料库。
private List<customer> _customers = new List<customer>();
private int _nextId = 1;//这个用途是拿来当作index
public CustomerRepository()
{
//总不能都是空吧>"<,所以一开始塞一些假资料。
this.Add(new Customer() { Name = "Sky", Phone = "0988888888" });
this.Add(new Customer() { Name = "Andy", Phone = "0977777777" });
this.Add(new Customer() { Name = "Tracy", Phone = "0966666666" });
}
//我们未来可以透过这个方法取得所有的资料
public IQueryable<customer> GetAll()
{
//反正就是回传整个List,并转成IQueryable型别
return _customers.AsQueryable();
}
//我们未来可以透过这个方法取得单笔资料
public Customer Get(int id)
{
//寻找符合id的资料
return _customers.Find(c => c.Id == id);
}
////我们未来可以透过这个方法新增资料
public Customer Add(Customer customer)
{
//index终于有用了,新增一笔前,我们先把目前的id给Customer.Id
//并且把_nextId++
customer.Id = _nextId++;
_customers.Add(customer);//加入List
return customer;
}
////我们未来可以透过这个方法删除资料
public bool Delete(int id)
{ //先找到目标
Customer customer = _customers.Find(c => c.Id == id);
//如果找不到,就回传False
if (customer == null)
{
return false;
}
//然后删除
_customers.Remove(customer);
return true;
}
////我们未来可以透过这个方法更新资料
public bool Update(Customer customer)
{
//先找找看index
int index = _customers.FindIndex(c => c.Id == customer.Id);
if (index == -1)
{
return false;
}
//更新资料
_customers[index].Name = customer.Name;
_customers[index].Phone = customer.Phone;
return true;
}
}
}
到目前为止,我们就把整个资料准备好了,到这边让小弟我休息一下,去泡的淡定红茶吧XDD。
后记
老实说,Repository算是一个不错的好物,不但有上面说的优点,更可以方便测试,而且未来针对Controller的部分,要写Unit Test就更加容易了,下一篇,我们会开始针对Web API,看看怎样配合Repository,并且把Web API给完成!。
前篇介绍了Model的实作,现在我们准备要进入Controller了喔,也就是开始撰写Web Service!REST
在开始写Controller之前,我们要稍微回忆一下REST风格,所谓的REST风格,就是同一个URI下,利用HTTP的四大命令"Get、Post、Put、Delete"来配合CRUD,而不像以前取得资料是一个网址,删除资料又是一个网址,我们可以看看下面的表。
URI | Get | Post | Put | Delete |
http://xxx/api/customer |
取得整组资料 | 新增整组资料 | 更新整组资料 | 删除整组资料 |
http://xxx/api/customer/12 |
取得单笔资料 | 新增单笔资料 | 更新单笔资料 | 删除单笔资料 |
从这边我们可以看到,URI ( 资源,其实就是一个网址 )都是同一个,但是我们针对不同的HTTP命令,就会有不同的效果,而这些效果刚好符合CRUD,而这边在强调一下,REST并不是一种规范,而是一种风格,利用HTTP的四大命令来对应资料库的CRUD,但实际是你也可以使用Get命令来执行DB的Delete,但这样就不符合REST风格了。
建立Web API吧
了解了这些规则后,接下来,我们要做的就是,如何使用ASP.NET MVC 建立符合REST风格的Web API;首先,第一步当然是先建立Controller噜,也就是这篇的主题。
接下来,先把CustomerController名称打好,但是这次的样板则是选择API controller with empty read/write actions这种样板了喔!
完成后,我们会发现,系统自动帮我们准备好了这些程式码,建立好的Class里面的Function,也刚好就是上头提到的Get、Post、Put、和Delete!!刚好就对应到HTTP的四个命令!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
namespace MvcWebApiCRUDDemo.Controllers
{
public class CustomerController : ApiController
{
// GET /api/customerontroller
public IEnumerable<STRING> Get()
{
return new string[] { "value1", "value2" };
}
// GET /api/customerontroller/5
public string Get(int id)
{
return "value";
}
// POST /api/customerontroller
public void Post(string value)
{
}
// PUT /api/customerontroller/5
public void Put(int id, string value)
{
}
// DELETE /api/customerontroller/5
public void Delete(int id)
{
}
}
}</STRING>
修改开始
不过这毕竟不是我们要的,如果能自动产生出我们想要的东西,就好了,但现实总是残酷的;所以我们要重新修改一下程式码,完成后的程式码会长这样,大家可以先看一下,细节我们下面会再仔细介绍。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using MvcWebApiCRUDDemo.Models;
using System.Net;
namespace MvcWebApiCRUDDemo.Controllers
{
public class CustomerController : ApiController
{
//建立一个静态的仓储,这里使用静态的目的是为了让资料可以被CRUD,
//而不会因,重新建立此仓储物件,而造成重塞资料的问题。
private static readonly ICustomerRepository _repository = new CustomerRepository();
// GET /api/customer
public IEnumerable<CUSTOMER> Get()
{
return _repository.GetAll();
}
// GET /api/customer/5
public Customer Get(int id)
{
Customer customer = _repository.Get(id);
if (customer == null)
{
//如果找不到,就抛出HTTP的Response例外,内容是寻找不到,也就是404
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return customer;
}
// POST /api/customer
public HttpResponseMessage Post(Customer customer)
{
customer = _repository.Add(customer);
var response = new HttpResponseMessage<CUSTOMER>(customer, HttpStatusCode.Created);
string uri = Url.Route(null, new { id = customer.Id });
response.Headers.Location = new Uri(Request.RequestUri, uri);
return response;
}
// PUT /api/customer/5
public void Put(int id, Customer customer)
{
customer.Id = id;
if (!_repository.Update(customer))
{
//如果找不到,就抛出HTTP的Response例外,内容是寻找不到,也就是404
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
// DELETE /api/customer/5
public HttpResponseMessage Delete(int id)
{
_repository.Delete(id);
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
}
}</CUSTOMER></CUSTOMER>
Repository
首先我们在这个Controller先建立一个static的Repository类别,这个类别就是我们上一章准备好的仓储物件,也就是会提供给我们新增修改Collection方法的地方 ( 别忘了,我们这个范例使用Collection来代替资料库 ),这边使用静态物件的原因,是因为,如果使用非静态物件,每次产生这个仓储物件时,都会自动塞资料到Collection,所以我们利用静态物件来处理,这样子,这个仓储物件,就只会产生一次,淡定的在那边=v=。
( 备注一下,并不是Repository Patten都要使用静态物件!这里使用静态的原因就如上面所说,但如果今天我们是针对资料库,我们就可以不需要使用静态物件,另外,有人可能会疑惑,为什么要使用介面,这其实是为了测试阿!!,当我们希望针对这个Controller进行Unit Test的时候,我们就可以Mock一个假的仓储物件,来"模拟"新增修改删除,所以这边才要使用介面,这也就是使用Repository Patten的精随。 )
private static readonly ICustomerRepository _repository = new CustomerRepository();
当有了仓储物件,我们就可以轻易地去做新增修改等方法,如下,这就是很典型的取得所有资料的方法。
_repository.GetAll();
就是这么简单。
Get
接下来,我们看看第一个Get方法,这个方法其实就会对应到HTTP的Get命令,简单的说,当我们对/api/customer这个URI,使用HTTP的Get命令,就会执行到这个Function,然后就会取得一堆JSON的资料,这就是ASP.NET MVC Web API的特色;当然,如果熟悉ASP.NET MVC的人,可能会想说,Get这个Action ( 对MVC来说Action其实就是个Function )的网址应该是xxx/Get阿!?以前不都是这样搞的吗!?,但不要怀疑,的确也可以像以前一样的网址,但这部分后续章节才会讲到。回头看Web API,Web API 里面的Function名称,如果取名为Get,就会对应到HTTP的Get命令,反正只要记住,在ASP.NET MVC Web API底下( 也就是继承了ApiController的Controller ),预设的Function名称,只要对应到HTTP四大命令的名称,就是会去对应到HTTP的四大命令。另外,如果有人看过ASP.NET MVC官网的范例,会发现,人家的范例是写GetAllContacts(),不用怀疑,其实Function的名称,只要前面有符合HTTP四大命令的名称,就会对应到了。
// GET /api/customer
public IEnumerable<CUSTOMER> Get()
{
return _repository.GetAll();
}</CUSTOMER>
如果使用IE进行分析,就可以看到对这个网址进行了GET请求。( 底下的图,是整个专案写完后,执行并截图下来的,因为View的地方还没有讲到,所以这边就只截分析的片段,等讲道View的部分,会再带大家看一次。 )
会回应JSON格式,没错,不用怀疑,ASP.NET MVC 预设就是回应JSON的格式,基本上JSON的格式还满简单的,如果对JSON不了解的人,可以参考一下这篇的中间,或是这篇的最后面有参考连结。
还是Get
接下来,我们继续往下看,接下来,还是Get,但这次的Get带了参数,没错,这个Get的用途就是取得单笔的资讯,我们可以透过/api/customer/5,来取得id为5的资料回来;而如果找不到,我们就会抛出一个例外,这个例外大家应该很熟习,就是传说中的404。
// GET /api/customer/5
public Customer Get(int id)
{
Customer customer = _repository.Get(id);
if (customer == null)
{
//如果找不到,就抛出HTTP的Response例外,内容是寻找不到,也就是404
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return customer;
}
我们会发现,还是使用Get( 废话XDD )。
这里只回应单笔了。
Post
然后接著的是Post,也就是准备要做新增的处理,但这里的新增有比较不一样的地方,首先,我们会将Customer这个Model传进去来处理,然后当然也是用仓储Class来进行新增的动作,但比较特别的返回型别,这里返回的是一个HttpReponseMessage,那是因为,Web API框架预设的回应状态为200(OK),但在HTTP/1.1的协定里面,如果使用POST创立一个资源时,因该是要返回201( Created ),这部分未来不知道正式版会不会修正,但现阶段,我们只能自己手写的方式( 或是直接拷贝贴上的方式XDD ),来处理201的状态,这也就是为什么需要返回一个HttpResponseMessage型别的原因;那这样就ok了吗?当然不,根据协定,除了要返回201以外,还必须在回应的Headers里面的Location加上新资源的URI,这样才是完整的!!反正结论就是必须加上下面这些东西,还是衷心的期望,正式版可以符合懒人小弟我的需求XDDD
// POST /api/customer
public HttpResponseMessage Post(Customer customer)
{
customer = _repository.Add(customer);
var response = new HttpResponseMessage<CUSTOMER>(customer, HttpStatusCode.Created);
string uri = Url.Route(null, new { id = customer.Id });
response.Headers.Location = new Uri(Request.RequestUri, uri);
return response;
}</CUSTOMER>
依照惯例,我们还是要贴一下图,这次我们使用了POST了。
然后我们可以看一下,送出去了那些东西 ( 好啦,我承认我懒惰,把名字和电话都打"2" )
接下来,我们可以看到,回应的部分,的确如预期是回应201 Created了,并且在Location里面有附上URI,因为是第四笔,所以后面多了4。
接下来,我们来看看Update。
Update
Update对应的其实就是HTTP的Put,这大家应该就比较少见了,但是其实还是依样简单,基本上带入两个参数,第一个参数id,是透过网址的方式传进来的,第二个参数Customer,未来则是会用JSON格式传递过来,那内容其实也很简单,毕竟我们将更新的方法都封装到Repository Class里面去了,我们只要简单的呼叫_repository.Update就可以了,如果回传false,就跳出错误讯息,代表找不到。
// PUT /api/customer/5
public void Put(int id, Customer customer)
{
customer.Id = id;
if (!_repository.Update(customer))
{
//如果找不到,就抛出HTTP的Response例外,内容是寻找不到,也就是404
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
这次使用PUT了,所以会看到,请求使用PUT命令,而且可以看到网址最后有1,表示我们更改第一笔。
这次稍微多打了几个字,我们把第一笔资料的name改为MS,phone也改为MS。( 由此可知,我们的UI和后面的Server端是完全没检查的XDDD,未来在教大家如何使用Model进行验证,方法和ASP.NET MVC的方法其实是一样的喔! )
Delete
终于写到最后一个了,写到快断气了= =,Delete通常都是号称最简单的XDD,( 破坏果然比建设容易 ),但这边比较特别的是,这里会返回一个204,也就是NoContent,根据HTTP/1.1,如果删除了,可以返回200,或是202 ( 表示已经接受,但还没删除 ),或是204 ( 代表的是完成了请求,且不需要返回任何东西 ),这里204是最适用于Delete,详细可以参考这里。
// DELETE /api/customer/5
public HttpResponseMessage Delete(int id)
{
_repository.Delete(id);
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
然后,我们依样看一下图,这次使用了DELETE命令。
回应的是204 No Contant。
后记
这篇又打了超久,但至少未来如果自己懒得打程式,也可以直接拷贝和贴上使用XDD;我们从这边可以感受到Repository Patten所带来的一些好处,也深深的了解到ASP.NET MVC Web API的写法,更加知道了Web Service应该回应的status,下一篇,我们将进入View的世界,使用JavaScript和jQuery来撰写AJAX的应用程式,来呼叫这里写好的Web Service!!
终于进入到View篇了,本来是预计一天把三篇写完的,结果没想到变成一个礼拜一篇= =,现在终于知道连载的辛苦了,富木坚,对不起以前都一直骂你XDD;回到主题,上一篇我们介绍到Controller,也把整个Web Service完成了,但是我们还没讲到要怎样利用JavaScript ( 利用jQuery这个函式库 )对Web Service进行呼叫阿!?所以我们这篇来谈谈View的部分。
jQuery
小弟就不再这边详细的介绍jQuery了,我相信很多人应该都会使用,这边只简单的介绍一下jQuery是做甚么的;jQuery 是一个非常方便,快速,程式码又简洁的JavaScript函式库,原本我们用JavaScript来进行DOM物件的寻找、处理事件、动画、浏览器版本还有Ajax等等,都会写非常多的程式码,所以就有位天才John Resig,写了jQuery来大幅的简化,总之,就是一个好物就是了;如果不会jQuery,可以参考一下jQuery的官网或是暗黑前辈的超完整教学,所以这部分小弟就不多介绍噜。
Knockout
这里必须还要再提一个东西,就是Knockout,他也是一个JavaScript的程式库,不过不用担心,小弟没那么惨忍XDD,一下要K Repository Patten,一下要看ASP.NET MVC Web API,一下又要看jQuery,所以这篇文章小弟不会用到Knockout;但为什么要提到这个呢!?那是因为目前这个东西也正是被纳入到ASP.NET MVC里面,而且官方的范例中,就是大量地使用到这个程式库,Knockout主要的用处是利用MVVM模式,来系节画面上的UI;详细可以参考暗黑前辈的Knockout这篇文章,或是官网,或是Andy前辈的FAQ Book;不过在一次的重申,这篇文章不会用到Knockout,所以可以放松心情的去读这几位前辈的文章=v=。
View
前面铺完路后,我们终于要正式开始撰写View了,不知道大家还记不记得,第一章的时候,那个空白的图?那时候我们建立起View后,并没有在View里面添加甚么,现在我们终于要开始加上一些东西了;首先,我们可以先打开如下图的档案,这就是我们第一章就准备好的档案。
我们首先先准备一下画面,我们预期的画面如下图,基本上和官网的差不多 ( 官网范例没有Delete喔XDD )。
HTML
接下来,HTML要怎样写哩,其实也没甚么特别的,就是利用了一些HTML5的标签 ( 毕竟已经是HTML5的时代了 ),然后准备好一个Table,来显示资料,并且准备一些输入栏位,以便后续的CRUD( 这里范例是用DIV标签来包输入栏位,当然也可以用DD、DT、或是li等标签,看个人喜好吧 ),当然,我们也要准备一些 Button来触发事件,所以我们准备了很多的Button ( 不是Submit按钮喔!!两个是有差异的。 ),来触发各种事件,完成大致上如下。( 眼力好的人,可能已经会发现Button里面已经有写准备触发的事件的Function名称了,我们等下就会把这些Function建立起来了喔! )
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div id="body">
<section class="content-wrapper main-content">
<h3>Contacts</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody id="customers">
</tbody>
</table>
</section>
<section id="detail" class="content-wrapper">
<h3>View Contact</h3>
<label for="contactId">ID</label>
<input type="text" title="ID" id="contactId" size="5" />
<input type="button" value="Get" οnclick="find();" />
<div>
<label for="name">Name</label>
<input type="text" title="Name" id="name" />
</div>
<div>
<label for="phone"> Phone</label>
<input type="text" title="Phone" id="phone" />
</div>
<div>
<input type="button" value="Update" οnclick="update();" />
<input type="button" value="Delete" οnclick="del();" />
<input type="button" value="Add New" οnclick="add();" />
</div>
<div>
<p id="status"></p>
</div>
</section>
</div>
</body>
</html>
接下来,我们稍微弄一下美化吧,所以我们利用CSS进行美化,( 再次强调,不要用HTML做为美化的工具,美化的职责应该是由CSS负责的喔!! )。
CSS
好,不用担心,我们没有用到CSS3,下面是个很简单的CSS,把CSS放到head标签底下;CSS的内容也超简单,基本上也只是把table、tr、th、td上个颜色,毕竟小弟现在不是要写CSS的笔记,所以稍微设定一下而已;另外,小弟特别把从头撷取index.cshtml的程式码,我想这样大家会比较了解CSS要放到哪边。
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<style type="text/css">
table
{
border: 1px solid #000;
border-collapse: collapse;
color: #666666;
min-width: 200px;
}
tr
{
border: 1px solid #000;
line-height: 25px;
}
th
{
background-color: #B1C3CC;
color: #000;
font-size: 13px;
text-align: left;
}
th, td
{
padding-left: 5px;
}
</style>
</head>
完成后,就会变成这样,有没有有没有,变漂亮了吧!!( 好吧,其实也没漂亮到哪去…但我们这篇的重点是jQuery和Web Service,小细节就不要计较了XDD)。
JavaScript & jQuery
好,完成画面后,就可以随便乱点了,然后就会在侦错工具出现这些错误( 记得侦错工具要打开…),这当然很正常,因为我们JavaScript还没开始写嘛。
接下来我们开始写JavaScript,以下是整个JavaScript,我们可以把整个JavaScript放到head标签里面,我们后面会针对细节做介绍。 ( 好的,我知道一些JavaScript放在head,效能等等之类的问题,但是,这不是我们这篇的重点=v= )
<script src="@Url.Content("~/Scripts/jquery-1.6.2.js")" type="text/javascript"></script>
<script type="text/javascript">
//清空status区段
function clearStatus() {
$('#status').html('');
}
var API_URL = "api/Customer/";
//增加资料
function add() {
clearStatus();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL,
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: json,
statusCode: {
201 /*Created*/: function (data) {
getAll();
}
}
});
}
//寻找资料
function find() {
clearStatus();
var id = $('#contactId').val();
if (id != "") {
$.getJSON(API_URL + id,
function (data) {
$("#customers tr").remove();
$("#customers").append("<tr>" +
"<td>" + data["Id"] + "</td>" +
"<td>" + data["Name"] + "</td>" +
"<td>" + data["Phone"] + "</td>" +
"</tr>");
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
} else {
getAll();
}
}
//更新资料
function update() {
clearStatus();
var id = $('#contactId').val();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL + id,
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//删除指定资料
function del() {
clearStatus();
var id = $('#contactId').val();
$.ajax({
url: API_URL + id,
cache: false,
type: 'DELETE',
contentType: 'application/json; charset=utf-8',
//data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//取得所有资料
function getAll() {
clearStatus();
//利用Get方式取得。
$.getJSON(API_URL,
function (data) {
$("#customers tr").remove();
for (i = 0; i < data.length; i++) {
$("#customers").append("<tr>" +
"<td>" + data[i].Id + "</td>" +
"<td>" + data[i].Name + "</td>" +
"<td>" + data[i].Phone + "</td>" +
"</tr>");
}
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//开始时,先把资料读取进来
$(document).ready(function () {
getAll();
});
</script>
接下来,我们针对每个细部,做一个讲解,有讲不好的地方,不要鞭我喔><。
清空
我们的第一个function,主要用途是清除status的资讯,在HTML里面,有一段会显示错误讯息等资讯,所以我们这边也要准备一下,清除这些资讯的Function。
//清空status区段
function clearStatus() {
$('#status').html('');
}
接下来继续。
取得全部
我们先来介绍取得全部的这个Funciton,也就是getAll(),我们这边利用jQuery的getJSON API进行处理,这个API预设会用HTTP的GET命令;当顺利取得资料的时候,就会把HTML table里面的东西移除掉,然后再利用回圈的方式,把取得的JSON资料和HTML标签td,一起塞到Table里面去。
//取得所有资料
function getAll() {
clearStatus();
//利用Get方式取得。
$.getJSON(API_URL,
function (data) {
$("#customers tr").remove();
for (i = 0; i < data.length; i++) {
$("#customers").append("<tr>" +
"<td>" + data[i].Id + "</td>" +
"<td>" + data[i].Name + "</td>" +
"<td>" + data[i].Phone + "</td>" +
"</tr>");
}
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
然后我们来看看新增。
ADD
第二段我们要讲的是ADD,但我们谈论ADD之前,我们要先设一个变数,负责记录网址位置,也就是API_URL;接下来,因为是新增,所以我们会需要准备传递资料,所以我们利用JSON.stringify来将我们填入表单的资料,转成JSON格式。然后我们就要利用jQuery的ajax API来对Web Service进行呼叫;还记得吗?HTTP的POST就是新增的意思,所以我们Type会设定POST,并且等传回201时,执行getAll()这个Function。
var API_URL = "api/Customer/";
//增加资料
function add() {
clearStatus();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL,
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: json,
statusCode: {
201 /*Created*/: function (data) {
getAll();
}
}
});
}
这样ADD就完成了,下图是执行结果,我们填入AA、AA的资料 ( Phone栏位没有验证,我真的知道><,是我的错。 ),按下AddNew后,画面会自动更新Table,出现第四笔资料;而下面的分析工具可以看到,真的送出了POST。
Find
接下来是寻找资料,其实寻找资料和getAll()很像,就不多加叙述了,但比较特别的是,我们会在网址 (API_URL)后面加上id,来寻找到想要找到的那一笔;如果没有找到,就会在status区块报错。
//寻找资料
function find() {
clearStatus();
var id = $('#contactId').val();
if (id != "") {
$.getJSON(API_URL + id,
function (data) {
$("#customers tr").remove();
$("#customers").append("<tr>" +
"<td>" + data["Id"] + "</td>" +
"<td>" + data["Name"] + "</td>" +
"<td>" + data["Phone"] + "</td>" +
"</tr>");
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
} else {
getAll();
}
}
执行结果如下,table会更新成寻到到的那笔,在下面的侦错视窗可以看到,利用了Get。
Update
更新资料和新增资料很像,一样是利用JSON.stringify来转换成JSON格式,然后用PUT来进行传送。
//更新资料
function update() {
clearStatus();
var id = $('#contactId').val();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL + id,
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
执行结果如下,我们ID、Name、Phone都填好后,按下Update就会更新资料,并且取得最新的table,我们也可以看到下面的侦错工具,可以发现到现在是用HTTP PUT命令。
Delete
删除资料更简单了,因为连JSON都不需要了,我们只要URL配合id,并且送出DELETE的指令就可以了!
//删除指定资料
function del() {
clearStatus();
var id = $('#contactId').val();
$.ajax({
url: API_URL + id,
cache: false,
type: 'DELETE',
contentType: 'application/json; charset=utf-8',
//data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
测试一下,我们填入要删除的ID,并按下Delete按钮,table就会自动更新,我们也可以从侦错视窗看到目前使用的是HTTP里面的Delete命令。
画面载入完成时
这是最后一小段的程式码,小弟我希望画面载入完成后,table会再动载入资料进来,所以加了这段。
//开始时,先把资料读取进来
$(document).ready(function () {
getAll();
});
到这边就大功告成,我们最后再把整个index.cshtml看一遍吧。
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<style type="text/css">
table
{
border: 1px solid #000;
border-collapse: collapse;
color: #666666;
min-width: 200px;
}
tr
{
border: 1px solid #000;
line-height: 25px;
}
th
{
background-color: #B1C3CC;
color: #000;
font-size: 13px;
text-align: left;
}
th, td
{
padding-left: 5px;
}
</style>
<script src="@Url.Content("~/Scripts/jquery-1.6.2.js")" type="text/javascript"></script>
<script type="text/javascript">
//清空status区段
function clearStatus() {
$('#status').html('');
}
var API_URL = "api/Customer/";
//增加资料
function add() {
clearStatus();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL,
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: json,
statusCode: {
201 /*Created*/: function (data) {
getAll();
}
}
});
}
//寻找资料
function find() {
clearStatus();
var id = $('#contactId').val();
if (id != "") {
$.getJSON(API_URL + id,
function (data) {
$("#customers tr").remove();
$("#customers").append("<tr>" +
"<td>" + data["Id"] + "</td>" +
"<td>" + data["Name"] + "</td>" +
"<td>" + data["Phone"] + "</td>" +
"</tr>");
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
} else {
getAll();
}
}
//更新资料
function update() {
clearStatus();
var id = $('#contactId').val();
var json = JSON.stringify({ name: $("#name").val(), phone: $("#phone").val() });
$.ajax({
url: API_URL + id,
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//删除指定资料
function del() {
clearStatus();
var id = $('#contactId').val();
$.ajax({
url: API_URL + id,
cache: false,
type: 'DELETE',
contentType: 'application/json; charset=utf-8',
//data: json,
success: function () { getAll(); }
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//取得所有资料
function getAll() {
clearStatus();
//利用Get方式取得。
$.getJSON(API_URL,
function (data) {
$("#customers tr").remove();
for (i = 0; i < data.length; i++) {
$("#customers").append("<tr>" +
"<td>" + data[i].Id + "</td>" +
"<td>" + data[i].Name + "</td>" +
"<td>" + data[i].Phone + "</td>" +
"</tr>");
}
})
.fail(
function (xhr, textStatus, err) {
$('#status').html('Error: ' + err);
});
}
//开始时,先把资料读取进来
$(document).ready(function () {
getAll();
});
</script>
</head>
<body>
<div id="body">
<section class="content-wrapper main-content">
<h3>Contacts</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody id="customers">
</tbody>
</table>
</section>
<section id="detail" class="content-wrapper">
<h3>View Contact</h3>
<label for="contactId">ID</label>
<input type="text" title="ID" id="contactId" size="5" />
<input type="button" value="Get" οnclick="find();" />
<div>
<label for="name">Name</label>
<input type="text" title="Name" id="name" />
</div>
<div>
<label for="phone"> Phone</label>
<input type="text" title="Phone" id="phone" />
</div>
<div>
<input type="button" value="Update" οnclick="update();" />
<input type="button" value="Delete" οnclick="del();" />
<input type="button" value="Add New" οnclick="add();" />
</div>
<div>
<p id="status"></p>
</div>
</section>
</div>
</body>
</html>
以上,终于写完!
后记
写完的当下,才发现KingKong前辈,和阿源哥哥前辈都有写过类似的文章 ( 晕倒 ),但不管怎样,这是小弟自己边看边写的读书笔记啦><,所以如果小弟没写好的地方,也可以去看看前辈们写的超详细文章喔!!