WebAPI从入门到精通.docx
《WebAPI从入门到精通.docx》由会员分享,可在线阅读,更多相关《WebAPI从入门到精通.docx(27页珍藏版)》请在冰豆网上搜索。
WebAPI从入门到精通
第1章.实例快速上手-ASP.NET4.5新特性WebAPI从入门到精通
在新出的MVC4中,增加了WebAPI,用于提供REST风格的WebService,新生成的WebAPI项目和典型的MVC项目一样,包含主要的Models、Views、Controllers等文件夹和Global.asax文件。
Views对于WebAPI来说没有太大的用途,Models中的Model主要用于保存Service和Client交互的对象,这些对象默认情况下会被转换为Json格式的数据迚行传输,Controllers中的Controller对应于WebService来说是一个Resource,用于提供服务。
和普通的MVC一样,Global.asax用于配置路由规则。
(1)环境准备
建议使用VS2012以上版本创建WebAPI,如果是使用VS2010,需要安装VS2010SP1升级包,MVC4升级包,打开VS2012创建如下:
第一步:
新建ASP.NETWeb应用程序
第二步:
建议WebAPI
新生成的WebAPI项目和典型的MVC项目一样,包含主要的Models,Views,Controllers等文件夹和Global.asax文件
注意:
再次强调Views对于WebAPI来说没有太大的用途,Models中的Model主要用于保存Service和Client交互的对象,这些对象默认情况下会被转换为Json格式的数据进行传输,Controllers中的Controller对应于WebService来说是一个Resource,用于提供服务。
和普通的MVC一样,Global.asax用于配置路由规则
(二)Models
和WCF中的数据契约形成鲜明对比的是,MVCWebAPI中的Model就是简单的POCO,没有任何别的东西,如,你可以创建如下的Model
publicclassUserModel
{
publicintId{get;set;}
publicstringUserName{get;set;}
publicstringPassWord{get;set;}
}
注意:
Model必须提供public的属性,用于json或xml反序列化时的赋值
(三)Controllers
MVCWebAPI中的Controllers和普通MVC的Controllers类似,不过不再继承于Controller,而改为继承API的ApiController,一个Controller可以包含多个Action,这些Action响应请求的方法与Global中配置的路由规则有关,在后面结束Global时统一说明
(四)Global
默认情况下,模板自带了两个路由规则,分别对应于WebAPI和普通MVC的Web请求,默认的WebAPI路由规则如下
1routes.MapHttpRoute(
2name:
"DefaultApi",
3routeTemplate:
"api/{controller}/{id}",
4defaults:
new{id=RouteParameter.Optional}
5);
可以看到,默认路由使用的固定的api作为Uri的先导,按照微软官方的说法,用于区分普通Web请求和WebService的请求路径:
可以看到,默认的路由规则只指向了Controller,没有指向具体的Action,因为默认情况下,对于Controller中的Action的匹配是和Action的方法名相关联的:
具体来说,如果使用上面的路由规则,对应下面的Controller:
publicclassUserController:
ApiController
{
publicListallModeList=newList(){
newUserModel(){Id=1,UserName="zhang",PassWord="123"},
newUserModel(){Id=2,UserName="lishi",PassWord="123456"},
newUserModel(){Id=3,UserName="wang",PassWord="1234567"}
};
//Getapi/User/
publicIEnumerableGetAll()
{
returnallModeList;
}
//Getapi/User/1
publicIEnumerableGetOne(intid){
returnallModeList.FindAll((m)=>{returnm.Id==id;});
}
//POSTapi/User/
publicboolPostNew(UserModeluser)
{
try
{
allModeList.Add(user);
returntrue;
}
catch{
returnfalse;
}
}
//Deleteapi/User/
publicintDeleteAll()
{
returnallModeList.RemoveAll((mode)=>{returntrue;});
}
//Deleteapi/User/1
publicintDeleteOne(intid){
returnallModeList.RemoveAll((m)=>{returnm.Id==id;});
}
//Putapi/User
publicintPutOne(intid,UserModeluser)
{
ListupDataList=allModeList.FindAll((mode)=>{returnmode.Id==id;});
foreach(varmodeinupDataList)
{
mode.PassWord=user.PassWord;
mode.UserName=user.UserName;
}
returnupDataList.Count;
}
}
则,会有下面的对应关系:
URLHttpMethod对应的Action名
/api/UserGETGetALL
/api/User/1GETGetOne
/api/UserPOSTPostNew
/api/User/1DELETEDeleteOne
/api/UserDELETEDeleteALL
/api/UserPUTPutOne
(5)客户端JS调用
functiongetAll(){
$.ajax({
url:
"api/User/",
type:
'GET',
success:
function(data){
document.getElementById("modes").innerHTML="";
$.each(data,function(key,val){
varstr=val.UserName+':
'+val.PassWord;
$('
',{html:
str}).appendTo($('#modes'));
});
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
functionfind(){
$.ajax({
url:
"api/User/1",
type:
'GET',
success:
function(data){
document.getElementById("modes").innerHTML="";
$.each(data,function(key,val){
varstr=val.UserName+':
'+val.PassWord;
$('
',{html:
str}).appendTo($('#modes'));
});
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
functionadd(){
$.ajax({
url:
"api/User/",
type:
"POST",
dataType:
"json",
data:
{"Id":
4,"UserName":
"admin","PassWord":
"666666"},
success:
function(data){
getAll();
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
functionremoveUser(){
$.ajax({
url:
"api/User/3",
type:
'DELETE',
success:
function(data){
document.getElementById("modes").innerHTML="";
getAll();
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
functionremoveAll(){
$.ajax({
url:
"api/User/",
type:
'DELETE',
success:
function(data){
document.getElementById("modes").innerHTML="";
getAll();
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
functionudpate(){
$.ajax({
url:
"api/User/1",
type:
'PUT',
dataType:
"json",
data:
{Id:
1,"UserName":
"admin","PassWord":
"666666"},
success:
function(data){
document.getElementById("modes").innerHTML="";
getAll();
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
这样就实现了最基本的CRUD操作。
扩展需求
问题1:
我想按照用户名称(UserName)进行查询,怎么办?
办法:
第一步:
在UserController类中加一个方法名称叫:
GetUserByName,如下所示:
publicUserModelGetUserByName(stringuserName){
returnallModeList.Find((m)=>{returnm.UserName.Equals(userName);});
}
第二步:
在客户端index.cshtml中调用
functiongetUserByName(){
$.ajax({
url:
"api/User/zhang",
type:
'GET',
success:
function(data){
document.getElementById("modes").innerHTML="";
varstr=data.UserName+':
'+data.PassWord;
$('
',{html:
str}).appendTo($('#modes'));
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
如果URL是:
url:
"api/User/zhang",将会报错:
BadRequest
原因是他会自动调用我们的GetOne(intid)这个方法,类型转换出错
解决办法:
改变URL为:
url:
"api/User/?
userName=zhang",
问题2:
我想按用户名称(UserName)和用户密码(PassWord)一起来进行查询,怎么办?
解决办法
第一步:
UserController类中,可以重载一个GetUserByName的方法,如下所示:
publicUserModelGetUserByName(stringuserName){
returnallModeList.Find((m)=>{returnm.UserName.Equals(userName);});
}
第二步:
客户端调用:
functiongetUserByName(){
$.ajax({
url:
"api/User/?
userName=zhang&passWord=123",//这里尤其需要注意
type:
'GET',
success:
function(data){
document.getElementById("modes").innerHTML="";
varstr=data.UserName+':
'+data.PassWord;
$('
',{html:
str}).appendTo($('#modes'));
}
}).fail(
function(xhr,textStatus,err){
alert('Error:
'+err);
});
}
(6)路由规则扩展
和普通的MVC一样,MVCWebAPI支持自定义的路由规则,如:
在上面的操作中,路由规则使用
"api/{controller}/{id}"
则限定了使用GET方式利用URL来传值时,controller后面的接收参数名为id,但是在Controller中,如果GetOne方法的接收参数名为key,是不会被匹配的,这是只需要新增一个新的路由规则,或修改原先的路由规则为:
"api/{controller}/{key}",如下所示:
config.Routes.MapHttpRoute(
name:
"DefaultApi",
routeTemplate:
"api/{controller}/{key}",
defaults:
new{key=RouteParameter.Optional}
);
当然,可以对路由进行更深的扩展,如:
扩展成和普通MVC一样的路由:
"api/{controller}/{action}/{id}"
这样,就要求同时使用Action和HTTP方法进行匹配
当然,根据微软的说法,这种使用是不被推荐的,因为这不符合大家对WebService的一般认知:
(7)使用Attribute声明HTTP方法
[HttpGet]
publicIEnumerableFindAll()
[HttpGet]
publicIEnumerableFindByKey(stringkey)
[HttpPost]
publicboolAdd(TestUseModemode)
[HttpDelete]
publicintRemoveByKey(stringkey)
[HttpDelete]
publicintRemoveAll()
[HttpPut]
publicintUpdateByKey(stringkey,stringvalue)
[NonAction]
publicstringGetPrivateData()
当然,我只列出了方法名,而不是这些方法真的没有方法体...方法体是不变的,NoAction表示这个方法是不接收请求的,即使以GET开头。
如果感觉常规的GET,POST,DELETE,PUT不够用,还可以使用AcceptVerbs的方式来声明HTTP方法,如:
[AcceptVerbs("MKCOL","HEAD")]
publicintUpdateByKey(stringkey,stringvalue)
{
ListupDataList=allModeList.FindAll((mode)=>{if(mode.ModeKey==key)returntrue;returnfalse;});
foreach(varmodeinupDataList)
{
mode.ModeValue=value;
}
returnupDataList.Count;
}
附:
什么是REST风格?
参考:
什么是REST风格
hi.baidu./yankaiwei/item/1f0b37dd922d53ef3cc2cb69
第二部分:
综合示例:
应用ASP.NETMVC4+WebAPI+FluentData开发Web应用
第一步:
创建数据库
NorthWind数据库的Customers表
CreateDataBaseNorthWind
Go
UseNorthWind
Go
CREATETABLE[dbo].[Customers](
[CustomerID][nchar](5)NOTNULL,
[CompanyName][nvarchar](40)NOTNULL,
[ContactName][nvarchar](30)NULL,
[ContactTitle][nvarchar](30)NULL,
[Address][nvarchar](60)NULL,
[City][nvarchar](15)NULL,
[Region][nvarchar](15)NULL,
[PostalCode][nvarchar](10)NULL,
[Country][nvarchar](15)NULL,
[Phone][nvarchar](24)NULL,
[Fax][nvarchar](24)NULL,
CONSTRAINT[PK_Customers]PRIMARYKEYCLUSTERED
(
[CustomerID]ASC
)WITH(PAD_INDEX=OFF,STATISTICS_NORECOMPUTE=OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)ON[PRIMARY]
)ON[PRIMARY]
GO
第二步:
创建FluentData.Entity层,创建Customer实体类
namespaceFluentData.Entity
{
publicclassCustomer
{
publicstringCustomerID{get;set;}
publicstringCompanyName{get;set;}
publicstringContactName{get;set;}
publicstringContactTitle{get;set;}
publicstringAddress{get;set;}
publicstringCity{get;set;}
publicstringRegion{get;set;}
publicstringPostalCode{get;set;}
publicstringCountry{get;set;}
publicstringPhone{get;set;}
publicstringFax{get;set;}
}
}
第三步:
利用FluentData做数据的持久化
首先引入FluentData.cs(见附件)
其次:
创建DBHelper类,代码如下:
publicclassDBHelper
{
publicstaticIDbContextContext(){
//returnnewDbContext().ConnectionString("server=127.0.0.1;uid=sa;pwd=sa;database=TestDB",newSqlServerProvider());
returnnewDbContext().ConnectionStringName("connString",newSqlServerProvider());
}
}
然后不要忘记修改ASP.NETMVC层所在的Web.config,加入数据库连结字符串:
第三步:
创建CustomerService数据持久化类,代码如下:
publicclassCustomerService
{
privateIDbContextcontext=DBHelper.Context();
publicCustomerSelect(stringcustomerId){
returncontext.Select("*").From("Customers").Where("CustomerID=0").Parameters(customerId)
.QuerySingle();
}
publicListSelectAll(){
returncontext.Select("*").From("Customers").QueryMany();
}
publicListSelectAll(stringsortEx