Web API控制器的编码
接下来,我们对已经生成了框架的Web控制器进行完善其中的代码,代码如下:
{
// Select All
public IEnumerable Get()
{
NorthwindEntities db = new NorthwindEntities();
var data = from item in db.Customers
orderby item.CustomerID
select item;
return data.ToList();
}
// Select By Id
public Customer Get( string id)
{
NorthwindEntities db = new NorthwindEntities();
var data = from item in db.Customers
where item.CustomerID == id
select item;
return data.SingleOrDefault();
}
//Insert
public void Post(Customer obj)
{
NorthwindEntities db = new NorthwindEntities();
db.Customers.AddObject(obj);
db.SaveChanges();
}
//Update
public void Put( string id, Customer obj)
{
NorthwindEntities db = new NorthwindEntities();
var data = from item in db.Customers
where item.CustomerID == id
select item;
Customer old = data.SingleOrDefault();
old.CompanyName = obj.CompanyName;
old.ContactName = obj.ContactName;
old.Country = obj.Country;
db.SaveChanges();
}
//Delete
public void Delete( string id)
{
NorthwindEntities db = new NorthwindEntities();
var data = from item in db.Customers
where item.CustomerID == id
select item;
Customer obj = data.SingleOrDefault();
db.Customers.DeleteObject(obj);
db.SaveChanges();
}
}
其中,Get()方法返回了Customers表中的所有数据,是以LIST列表的形式返回的。customer表中的主键为CustomerId列,并且是字符串类型,因此,另外的一个get带参数的方法,是根据传入的ID参数返回了某一个customer的对象实例。
Post()方法则接收一个Customer对象作为参数,并且将其新增到数据表中去,同样,Put()方法中,接收一个customerid,然后在数据表中找出该customer对象,为该customer对象的属性重新赋值,然后再保存;最后Delete方法根据传入的CustomerID参数删除数据表中的数据并保存。
从浏览器中访问WEB API
在通过普通页面作为客户端访问Web API前,首先在浏览器中通过输入地址的方法先测试一下,如下图:
注意的是,访问API的方式为:localhost/api/customers,在实际中将要根据情况替换合适的端口,默认所有的WEB API都是通过/api根目录的方式访问的,该路由是在Global.asax下进行定义,如下:
{
...
routes.MapHttpRoute(
name: " DefaultApi ",
routeTemplate: " api/{controller}/{id} ",
defaults: new { id = RouteParameter.Optional }
);
...
}
因此,现在由于我们的WEB API控制器是customers,因此如何要得到某个顾客的信息,可以如下的方式访问:
/api/customers/ALFKI
创建自定义JSON格式化器
在通过浏览器去访问WEB API时,默认的显示方式是XML。Web API框架会自动根据访问客户端的不同从而返回不同的格式的数据。现在,大多数情况下,用户希望返回的格式数据是JSON形式。然而,在本文写作时,使用默认的Web API提供的JSON格式化处理器以及Entity Framework搭配工作时,会出现一些小BUG.The entities of the EF data model have IsReference property of DataContractAttribute set to True.EF EF数据模型的实体将DataContractAttribute中的IsReference属性设置为true,如下:
[Serializable()]
[DataContractAttribute(IsReference= true)]
public partial class Customer : EntityObject
{
...
}
默认情况下,Web API使用的是DataContractJsonSerializer类进行JSON序列化。但默认的JSON序列化类不能处理这样的实体类,并且在运行期间抛出如下异常:
The type 'WebAPIDemo.Models.Customer' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.
为了克服则个问题,可以创建一个自定义的JSON格式化器。幸运的是,有第三方的JSON序列化器给我们选择使用,比如Json.NET。在本文中,将会简单介绍使用JSON.NET去完成序列化,完整的代码可以在附件中下载。
一个自定义的序列化器主要是继承了MediaTypeFormatter的基类。我们编写的这个JSON序列化类为JsonNetFormatter,在使用前要确认你的应用工程中已经引用了Json.NET的类库,如下图:
下面我们来看下JsonNetFormatter的基础代码:
{
...
}
可以通过重写MediaTypeFormatter中的一些方法如下:
{
...
}
protected override bool CanWriteType(Type type)
{
...
}
protected override Task< object> OnReadFromStreamAsync(Type type, Stream stream,
HttpContentHeaders contentHeaders,
FormatterContext formatterContext)
{
...
}
protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream,
HttpContentHeaders contentHeaders,
FormatterContext formatterContext,
TransportContext transportContext)
{
...
}
具体的代码在附件中可以详细查看。一旦创建了JSON序列化器后,就需要告诉Web API框架去替换使用原先默认的JSON序列化框架。可以在global.asx中实现:
{
HttpConfiguration config = GlobalConfiguration.Configuration;
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add( new IsoDateTimeConverter());
JsonNetFormatter formatter = new WebAPIDemo.Http.Formatters.JsonNetFormatter(settings);
config.Formatters.Insert( 0, formatter);
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
}
其中请注意粗体字部分,这里创建了JSON自定义器的实例,并且增加到以HttpConfiguration类的配制的序列化配制集合中。
这样,我们就可以开始在客户端中调用WEB API,并使用自定义的JSON解析器进行处理
当页面加载时,使用GET()方法去调出customer表的所有数据,而当使用INSERT,UPDATE,DELETE功能时,是通过jQuery去调用web api的。下面我们学习下通过jQuery去调用WEB API。
首先,我们设计每一行的HTML代码,如下:
<tr>
<th>Customer ID</th>
<th>Company Name</th>
<th>Contact Name</th>
<th>Country</th>
<th>Actions</th>
</tr>
<tr>
<td><input type= " text " id= " txtCustomerId " size= " 5 "/></td>
<td><input type= " text " id= " txtCompanyName " /></td>
<td><input type= " text " id= " txtContactName " /></td>
<td><input type= " text " id= " txtCountry " /></td>
<td><input type= " button " name= " btnInsert " value= " Insert " /></td>
</tr>
</table>
首先要引入jQuery类库:
然后在jQuery中,通过$.getJSON的方法,调用WEB API,代码如下:
$(document).ready(function () {
$.getJSON("api/customers", LoadCustomers);
});
熟悉jQuery的朋友肯定明白,$.getJson方法中第一个参数是调用服务的地址,第二个参数是回调方法,这个回调方法LoadCustomers中,将展示服务端web api返回的数据,代码如下:
$( " #customerTable ").find( " tr:gt(1) ").remove();
$.each(data, function (key, val) {
var tableRow = ' <tr>' +
' <td>' + val.CustomerID + '</td>' +
' <td><input type="text" value="' + val.CompanyName + '"/></td>' +
' <td><input type="text" value="' + val.ContactName + '"/></td>' +
' <td><input type="text" value="' + val.Country + '"/></td>' +
' <td><input type="button" name="btnUpdate" value="Update" />
<input type= " button " name= " btnDelete " value= " Delete " /></td> ' +
' </tr>';
$( ' #customerTable').append(tableRow);
});
$( " input[name='btnInsert'] ").click(OnInsert);
$( " input[name='btnUpdate'] ").click(OnUpdate);
$( " input[name='btnDelete'] ").click(OnDelete);
}
在上面的代码中,首先移除所有表格中的行(除了表头外),然后通过jQuery中的each方法,遍历web api返回给前端的数据,最后展现所有的数据行。然后在Insert,update,delete三个按钮中都绑定了相关的方法函数,下面先看update的代码:
var cell;
var customerId = $(this).parent().parent().children().get( 0).innerHTML;
cell = $(this).parent().parent().children().get( 1);
var companyName = $(cell).find( ' input').val();
cell = $(this).parent().parent().children().get( 2);
var contactName = $(cell).find( ' input').val();
cell = $(this).parent().parent().children().get( 3);
var country = $(cell).find( ' input').val();
var data = ' {"id":"' + customerId + '", "obj":{"CustomerID":"' + customerId +
' ","CompanyName":"' + companyName + '","ContactName":"' +
contactName + ' ","Country":"' + country + '"}}';
$.ajax({
type: ' PUT',
url: ' /api/customers/',
data: data,
contentType: " application/json; charset=utf-8 ",
dataType: ' json',
success: function (results) {
$.getJSON( " api/customers ", LoadCustomers);
alert( ' Customer Updated !');
}
})
}
在上面的代码中,首先从每行的各个文本框中获得要更新的值,然后组织成JSON数据,
其数据格式为包含两项,其中一项包含customer的ID,另外一个是新的customer实体对象,因为WEB API的PUT方法需要的是两个参数。
然后通过jQuery的$.ajax方法进行调用web api,注意这里的type指定为put方法,并且注意编码为UTF-8,然后在回调方法success中,再此使用$.getJSON方法,获得更新后的最新用户列表。
而Insert,Delete的方法代码如下:
var customerId = $( " #txtCustomerId ").val();
var companyName = $( " #txtCompanyName ").val();
var contactName = $( " #txtContactName ").val();
var country = $( " #txtCountry ").val();
var data = ' {"obj":{"CustomerID":"' + customerId + '","CompanyName":"' + companyName +
' ","ContactName":"' + contactName + '","Country":"' + country + '"}}';
$.ajax({
type: ' POST',
url: ' /api/customers/',
data: data,
contentType: " application/json; charset=utf-8 ",
dataType: ' json',
success: function (results) {
$( " #txtCustomerId ").val( ' ');
$( " #txtCompanyName ").val( ' ');
$( " #txtContactName ").val( ' ');
$( " #txtCountry ").val( ' ');
$.getJSON( " api/customers ", LoadCustomers);
alert( ' Customer Added !');
}
})
}
function OnDelete(evt) {
var customerId = $(this).parent().parent().children().get( 0).innerHTML;
var data = ' {"id":"' + customerId + '"}';
var row = $(this).parent().parent();
$.ajax({
type: ' DELETE',
url: ' /api/customers/',
data: data,
contentType: " application/json; charset=utf-8 ",
dataType: ' json',
success: function (results) {
$.getJSON( " api/customers ", LoadCustomers);
alert( ' Customer Deleted!');
}
})
}
读者要注意的是,在实际应用中,可以使用含有GET,PUT,DELETE前缀的方法名,比如
GetXXXX(), PutXXXX(), PostXXXX()都是可以的,XXX是自定义的名称,WEB API框架依然会调用对应的GET,PUT和POST方法。